~starkingdoms/starkingdoms

ref: 494c0b1ca0e58be47c24cf6fd937b57dea1cd1f5 starkingdoms/crates/client/src/rendering/assets_wasm.rs -rw-r--r-- 5.4 KiB
494c0b1c — ghostly_zsh player and parts rendering, but jk it doesnt work 9 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use std::{collections::HashMap, fmt::Display, sync::{Arc, Mutex}};

use bevy_ecs::system::Resource;
use futures::channel::oneshot::Receiver;
use image::EncodableLayout;
use resvg::{tiny_skia, usvg};
use wasm_bindgen_futures::spawn_local;

#[derive(Debug, Clone)]
pub enum AssetError {
    AssetNotFound,
    ResponseNotOk(u16),
}
impl Display for AssetError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AssetError::AssetNotFound => write!(f, "Asset not found"),
            AssetError::ResponseNotOk(code) => write!(f, "Server response was not ok {}", code),
        }
    }
}
impl std::error::Error for AssetError {}

#[derive(Debug, Clone)]
pub struct ImgData {
    pub bytes: Vec<u8>,
    pub width: u32,
    pub height: u32,
}

#[derive(Resource)]
pub struct Assets {
    texture_receivers: Arc<Mutex<HashMap<String, Receiver<ImgData>>>>,
    textures: Arc<Mutex<HashMap<String, ImgData>>>,
}

impl Assets {
    pub fn new() -> Self {
        Assets {
            textures: Arc::new(Mutex::new(HashMap::new())),
            texture_receivers: Arc::new(Mutex::new(HashMap::new())),
        }
    }
    pub fn get(&self, local_path: impl Into<String>) -> Option<ImgData> {
        let (tx, rx) = futures::channel::oneshot::channel();
        let local_path = local_path.into();
        let contains_texture = {
            self.textures.lock().unwrap().contains_key(&local_path)
        };
        let contains_texture_receiver = {
            self.texture_receivers.lock().unwrap().contains_key(&local_path)
        };
        if !contains_texture && !contains_texture_receiver {
            let textures = self.textures.clone();
            {
                self.texture_receivers.lock().unwrap().insert(local_path.clone(), rx);
            }
            spawn_local(async move {
                let window = web_sys::window().unwrap();
                let resp = match reqwest::get(format!("{}/src/textures/{}", window.location().origin().unwrap(), local_path)).await {
                    Ok(resp) => resp,
                    Err(e) => {
                        if e.is_request() {
                            panic!("Error in request {}", e);
                        } else if e.is_body() {
                            panic!("Error in body {}", e);
                        } else if e.is_status() {
                            panic!("Bad status: {}", e.status().unwrap());
                        } else if e.is_decode() {
                            panic!("Couldn't decode response's body {}", e);
                        } else if e.is_redirect() {
                            panic!("Response caused redirect loop {}", e);
                        } else if e.is_builder() {
                            panic!("Error in builder {}", e);
                        }
                        panic!();
                    },
                };
                let bytes = match resp.bytes().await {
                    Ok(bytes) => bytes,
                    Err(e) => todo!(),
                }.to_vec();
                if local_path.ends_with(".svg") {
                    let opt = usvg::Options {
                        default_size: usvg::Size::from_wh(20.0, 20.0).unwrap(),
                        ..Default::default()
                    };
                    let tree = usvg::Tree::from_data(&bytes, &opt).expect(&format!("Couldn't parse svg {}", local_path));
                    let tree_size = tree.size().to_int_size();
                    let size = usvg::Size::from_wh(100.0, 100.0).unwrap().to_int_size();
                    assert!(size.width() > 0 && size.height() > 0);
                    let mut pixmap = tiny_skia::Pixmap::new(size.width(), size.height()).expect("Failed to construct pixmap");
                    resvg::render(&tree, tiny_skia::Transform::from_scale((size.width() as f32)/(tree_size.height() as f32), (size.height() as f32)/(tree_size.height() as f32)), &mut pixmap.as_mut());
                    let data = ImgData {
                        bytes: pixmap.data().to_vec(),
                        width: size.width(),
                        height: size.height(),
                    };
                    
                    {
                        textures.lock().unwrap().insert(local_path, data.clone());
                    }
                    tx.send(data).unwrap();
                } else if local_path.ends_with(".png") {
                    let img = image::load_from_memory(&bytes).unwrap();
                    let rgba = img.to_rgba8();
                    let data = ImgData {
                        bytes: rgba.as_bytes().to_vec(),
                        width: rgba.width(),
                        height: rgba.height(),
                    };
                    {
                        textures.lock().unwrap().insert(local_path, data.clone());
                    }
                    tx.send(data).unwrap();
                }
            });
            None
        } else if !contains_texture {
            let mut texture_receivers = self.texture_receivers.lock().unwrap();
            let rx = texture_receivers.get_mut(&local_path).unwrap();
            if let Ok(Some(texture)) = rx.try_recv() {
                self.texture_receivers.lock().unwrap().remove(&local_path);
                self.textures.lock().unwrap().insert(local_path, texture.clone());
                return Some(texture);
            }
            None
        } else {
            self.textures.lock().unwrap().get(&local_path).cloned()
        }
    }
}