nesbox_utils_macro 0.0.3

macro provided for nesbox_utils
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};

#[proc_macro_attribute]
pub fn nesbox_bevy(_: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as ItemFn);
    let create_app = &input.sig.ident;
    let tokens = quote! {
        #input

        #[wasm_bindgen]
        pub struct Nes {
            app: App,
            prev_frame_buffer: Vec<u8>,
            qoi_buffer: Vec<u8>,
            qoi_decode_buffer: Vec<u8>,
        }

        #[wasm_bindgen]
        impl Nes {
            pub fn new(_output_sample_rate: f32) -> Self {
                log!("Create bevy app...");
                Self {
                    app: #create_app(),
                    prev_frame_buffer: Vec::new(),
                    qoi_buffer: Vec::new(),
                    qoi_decode_buffer: Vec::new(),
                }
            }

            pub fn mem(&mut self) -> JsValue {
                wasm_bindgen::memory()
            }

            pub fn width(&self) -> u32 {
                self.app
                    .world
                    .get_resource::<PixelsResource>()
                    .unwrap()
                    .width
            }

            pub fn height(&self) -> u32 {
                self.app
                    .world
                    .get_resource::<PixelsResource>()
                    .unwrap()
                    .height
            }

            pub fn sound(&mut self) -> bool {
                self.app
                    .world
                    .get_resource::<AudioResource>()
                    .unwrap()
                    .sound()
            }

            pub fn set_sound(&mut self, enabled: bool) {
                self.app
                    .world
                    .get_resource_mut::<AudioResource>()
                    .unwrap()
                    .set_sound(enabled);
            }

            pub fn reset(&mut self) {
                //
            }

            pub fn frame(&mut self, qoi: bool, qoi_whole_frame: bool) -> *const u8 {
                let binding = self.app.world.get_resource::<PixelsResource>().unwrap();
                let buffer = binding.frame();
                if qoi {
                    self.qoi_buffer = encode_qoi_frame(
                        &self.prev_frame_buffer,
                        buffer,
                        self.width(),
                        qoi_whole_frame,
                    );
                    self.prev_frame_buffer = buffer.to_vec();
                } else {
                    self.prev_frame_buffer = Vec::new();
                }
                buffer.as_ptr()
            }

            pub fn frame_len(&self) -> usize {
                self.app
                    .world
                    .get_resource::<PixelsResource>()
                    .unwrap()
                    .frame()
                    .len()
            }

            pub fn qoi_frame(&mut self) -> *const u8 {
                self.qoi_buffer.as_ptr()
            }

            pub fn qoi_frame_len(&self) -> usize {
                self.qoi_buffer.len()
            }

            pub fn decode_qoi(&mut self, bytes: &[u8]) -> *const u8 {
                self.qoi_decode_buffer = decode_qoi_frame(bytes);
                self.qoi_decode_buffer.as_ptr()
            }

            pub fn decode_qoi_len(&self) -> usize {
                self.qoi_decode_buffer.len()
            }

            pub fn audio_callback(&mut self, out: &mut [f32]) {
                let binding = self.app.world.get_resource::<AudioResource>().unwrap();
                let buffer = binding.frame();
                out.copy_from_slice(buffer);
            }

            pub fn clock_frame(&mut self) -> u32 {
                self.app.update();
                self.app
                    .world
                    .get_resource_mut::<ButtonInput>()
                    .unwrap()
                    .clear();
                self.app.world.get_resource::<FrameCount>().unwrap().0
            }

            pub fn load_rom(&mut self, mut _bytes: &[u8]) {
                //
            }

            pub fn handle_button_event(&mut self, player: Player, button: Button, pressed: bool) {
                let mut input = self.app.world.get_resource_mut::<ButtonInput>().unwrap();
                let mut input = input.get_input_mut(player);
                if pressed {
                    input.press(button);
                } else {
                    input.release(button);
                }
            }

            pub fn handle_motion_event(&mut self, player: Player, x: f32, y: f32, dx: f32, dy: f32) {
                let mut system_state: SystemState<EventWriter<MouseEvent>> =
                    SystemState::new(&mut self.app.world);
                let mut mouse_motion = system_state.get_mut(&mut self.app.world);

                mouse_motion.send(MouseEvent {
                    player,
                    delta: Vec2::new(dx, dy),
                    position: Vec2::new(x, y),
                });
            }

            pub fn state(&mut self) -> Vec<u8> {
                Vec::new()
            }

            pub fn load_state(&mut self, _state: &[u8]) {
                //
            }

            pub fn ram_map(&mut self) -> Vec<u32> {
                Vec::new()
            }

            pub fn ram(&mut self) -> Vec<u8> {
                Vec::new()
            }

            pub fn read_ram(&mut self, _addr: u16) -> u8 {
                0
            }

            pub fn write_ram(&mut self, _addr: u16, _val: u8) {
                //
            }
        }
    };

    tokens.into()
}