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
use crate::context::RESOURCE_TABLE;
use crate::graphics::GraphicsApi;
use rask_engine::resources::{registry, GetStore, TextureIds};
use rask_wasm_shared::error::ClientError;
use rask_wasm_shared::{get_double_buffer, SynchronizationMemory};

pub struct Render<T> {
    graphics: T,
    frame_nr: u64,
    used_texture_ids: Vec<u32>,
}

impl<T: GraphicsApi> Render<T> {
    pub fn new(canvas: web_sys::OffscreenCanvas) -> Result<Self, ClientError> {
        let factor = rask_engine::math::vec2::Vec2::new(0.2, 0.2);
        T::new(canvas, factor).map(|api| Self {
            graphics: api,
            frame_nr: 0,
            used_texture_ids: vec![],
        })
    }

    pub fn render(&mut self) -> Result<(), ClientError> {
        self.graphics
            .ok()
            .map_err(|e| ClientError::WebGlError(format!("WebGl2 error: {}", e)))?;
        let size = (unsafe { SynchronizationMemory::get() }).canvas_size;
        self.graphics.update_size(size.0, size.1);
        self.graphics.start_frame(&[0.0, 0.0, 0.0])?;
        if self.draw_sprites()? {
            self.frame_nr += 1;
        }
        self.graphics.end_frame()
    }

    pub fn upload_texture(&mut self, id: u32) -> Result<(), ClientError> {
        let texture = unsafe { RESOURCE_TABLE.get(id as usize)? };
        self.graphics.resize_texture_pool(id + 1)?;
        self.graphics.upload_texture(texture, id)?;
        if !self.used_texture_ids.contains(&id) {
            self.used_texture_ids.push(id)
        }
        Ok(())
    }

    pub fn unload_texture(&mut self, id: u32) -> Result<(), ClientError> {
        let texture = unsafe { RESOURCE_TABLE.get(id as usize)? };
        self.graphics.resize_texture_pool(id + 1)?;
        self.graphics.upload_texture(texture, id)?;
        Ok(())
    }

    pub fn reset_textures(&mut self, used_textures: &TextureIds) -> Result<(), ClientError> {
        for texture in self.used_texture_ids.clone().iter() {
            if !used_textures.ids.contains(texture) {
                self.unload_texture(*texture);
                self.used_texture_ids.swap_remove(*texture as usize);
            }
        }
        unsafe { *(used_textures.reset_notify as *mut u8) = 0 };
        Ok(())
    }

    pub fn draw_sprites(&mut self) -> Result<bool, ClientError> {
        let used_textures = unsafe { RESOURCE_TABLE.get(registry::USED_TEXTURE_IDS.id as usize) };
        if let Err(rask_engine::EngineError::ResourceMissing(_)) = used_textures {
            return Ok(true);
        }
        let used_textures: &TextureIds = used_textures?;
        if used_textures.reset_notify >= 0 {
            self.reset_textures(used_textures);
        }
        if let Some(state) = get_double_buffer().borrow_reader() {
            let state = state.get();
            let sprites = state.sprites();
            for sprite in sprites {
                if self
                    .graphics
                    .draw_rect(&sprite.transform, sprite.tex_id)?
                    .is_none()
                {
                    self.upload_texture(sprite.tex_id)?;
                    self.graphics
                        .draw_rect(&sprite.transform, sprite.tex_id)?
                        .unwrap();
                }
            }
            Ok(true)
        } else {
            Ok(false)
        }
    }
}