VIP inspection tooling #4
			
				
			
		
		
		
	
							
								
								
									
										81
									
								
								src/vram.rs
								
								
								
								
							
							
						
						
									
										81
									
								
								src/vram.rs
								
								
								
								
							| 
						 | 
					@ -1,13 +1,13 @@
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    collections::{hash_map::Entry, HashMap},
 | 
					    collections::{hash_map::Entry, HashMap},
 | 
				
			||||||
    hash::Hash,
 | 
					    hash::Hash,
 | 
				
			||||||
    sync::Mutex,
 | 
					    sync::{Arc, Mutex},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use egui::{
 | 
					use egui::{
 | 
				
			||||||
    epaint::ImageDelta,
 | 
					    epaint::ImageDelta,
 | 
				
			||||||
    load::{LoadError, SizedTexture, TextureLoader, TexturePoll},
 | 
					    load::{LoadError, SizedTexture, TextureLoader, TexturePoll},
 | 
				
			||||||
    ColorImage, Context, TextureHandle, TextureOptions,
 | 
					    Color32, ColorImage, Context, TextureHandle, TextureOptions,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,21 +27,60 @@ impl<T: Serialize + for<'a> Deserialize<'a> + PartialEq + Eq + Hash> VramResourc
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum VramImage {
 | 
				
			||||||
 | 
					    Unchanged(Arc<ColorImage>),
 | 
				
			||||||
 | 
					    Changed(ColorImage),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl VramImage {
 | 
				
			||||||
 | 
					    pub fn new(width: usize, height: usize) -> Self {
 | 
				
			||||||
 | 
					        Self::Changed(ColorImage::new([width, height], Color32::BLACK))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn write(&mut self, coords: (usize, usize), shade: u8) {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Unchanged(image) => {
 | 
				
			||||||
 | 
					                let value = image[coords];
 | 
				
			||||||
 | 
					                if value.r() == shade {
 | 
				
			||||||
 | 
					                    return;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let mut new_image = ColorImage::clone(image);
 | 
				
			||||||
 | 
					                new_image[coords] = Color32::from_gray(shade);
 | 
				
			||||||
 | 
					                *self = Self::Changed(new_image);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Self::Changed(image) => {
 | 
				
			||||||
 | 
					                image[coords] = Color32::from_gray(shade);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn take(&mut self) -> Option<Arc<ColorImage>> {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Unchanged(_) => None,
 | 
				
			||||||
 | 
					            Self::Changed(image) => {
 | 
				
			||||||
 | 
					                let arced = Arc::new(std::mem::take(image));
 | 
				
			||||||
 | 
					                *self = Self::Unchanged(arced.clone());
 | 
				
			||||||
 | 
					                Some(arced)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait VramImageLoader {
 | 
					pub trait VramImageLoader {
 | 
				
			||||||
    type Resource: VramResource;
 | 
					    type Resource: VramResource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn id(&self) -> &str;
 | 
					    fn id(&self) -> &str;
 | 
				
			||||||
    fn add(&self, resource: &Self::Resource) -> Option<ColorImage>;
 | 
					    fn add(&self, resource: &Self::Resource) -> Option<VramImage>;
 | 
				
			||||||
    fn update<'a>(
 | 
					    fn update<'a>(
 | 
				
			||||||
        &'a self,
 | 
					        &'a self,
 | 
				
			||||||
        resources: impl Iterator<Item = &'a Self::Resource>,
 | 
					        resources: impl Iterator<Item = (&'a Self::Resource, &'a mut VramImage)>,
 | 
				
			||||||
    ) -> Vec<(&'a Self::Resource, ColorImage)>;
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct VramTextureLoader<T: VramImageLoader> {
 | 
					pub struct VramTextureLoader<T: VramImageLoader> {
 | 
				
			||||||
    id: String,
 | 
					    id: String,
 | 
				
			||||||
    loader: Mutex<T>,
 | 
					    loader: Mutex<T>,
 | 
				
			||||||
    cache: Mutex<HashMap<T::Resource, TextureHandle>>,
 | 
					    cache: Mutex<HashMap<T::Resource, (TextureHandle, VramImage)>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: VramImageLoader> VramTextureLoader<T> {
 | 
					impl<T: VramImageLoader> VramTextureLoader<T> {
 | 
				
			||||||
| 
						 | 
					@ -76,26 +115,30 @@ impl<T: VramImageLoader> TextureLoader for VramTextureLoader<T> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let loader = self.loader.lock().unwrap();
 | 
					        let loader = self.loader.lock().unwrap();
 | 
				
			||||||
        let mut cache = self.cache.lock().unwrap();
 | 
					        let mut cache = self.cache.lock().unwrap();
 | 
				
			||||||
        for (resource, updated_image) in loader.update(cache.keys()) {
 | 
					        let resources = cache.iter_mut().map(|(k, v)| (k, &mut v.1));
 | 
				
			||||||
            if let Some(handle) = cache.get(resource) {
 | 
					        loader.update(resources);
 | 
				
			||||||
                let delta = ImageDelta::full(updated_image, TextureOptions::NEAREST);
 | 
					        for (handle, image) in cache.values_mut() {
 | 
				
			||||||
 | 
					            if let Some(data) = image.take() {
 | 
				
			||||||
 | 
					                let delta = ImageDelta::full(data, TextureOptions::NEAREST);
 | 
				
			||||||
                ctx.tex_manager().write().set(handle.id(), delta);
 | 
					                ctx.tex_manager().write().set(handle.id(), delta);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        match cache.entry(resource) {
 | 
					        match cache.entry(resource) {
 | 
				
			||||||
            Entry::Occupied(entry) => {
 | 
					            Entry::Occupied(entry) => {
 | 
				
			||||||
                let texture = SizedTexture::from_handle(entry.get());
 | 
					                let texture = SizedTexture::from_handle(&entry.get().0);
 | 
				
			||||||
                Ok(TexturePoll::Ready { texture })
 | 
					                Ok(TexturePoll::Ready { texture })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Entry::Vacant(entry) => {
 | 
					            Entry::Vacant(entry) => {
 | 
				
			||||||
                if let Some(image) = loader.add(entry.key()) {
 | 
					                let Some(mut image) = loader.add(entry.key()) else {
 | 
				
			||||||
                    let handle =
 | 
					                    return Err(LoadError::Loading("could not load texture".into()));
 | 
				
			||||||
                        entry.insert(ctx.load_texture(uri, image, TextureOptions::NEAREST));
 | 
					                };
 | 
				
			||||||
                    let texture = SizedTexture::from_handle(handle);
 | 
					                let Some(data) = image.take() else {
 | 
				
			||||||
                    Ok(TexturePoll::Ready { texture })
 | 
					                    return Err(LoadError::Loading("could not load texture".into()));
 | 
				
			||||||
                } else {
 | 
					                };
 | 
				
			||||||
                    Err(LoadError::Loading("could not load texture".into()))
 | 
					                let handle = ctx.load_texture(uri, data, TextureOptions::NEAREST);
 | 
				
			||||||
                }
 | 
					                let (handle, _) = entry.insert((handle, image));
 | 
				
			||||||
 | 
					                let texture = SizedTexture::from_handle(handle);
 | 
				
			||||||
 | 
					                Ok(TexturePoll::Ready { texture })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -115,7 +158,7 @@ impl<T: VramImageLoader> TextureLoader for VramTextureLoader<T> {
 | 
				
			||||||
            .lock()
 | 
					            .lock()
 | 
				
			||||||
            .unwrap()
 | 
					            .unwrap()
 | 
				
			||||||
            .values()
 | 
					            .values()
 | 
				
			||||||
            .map(|h| h.byte_size())
 | 
					            .map(|h| h.0.byte_size())
 | 
				
			||||||
            .sum()
 | 
					            .sum()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
use std::sync::Arc;
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use egui::{
 | 
					use egui::{
 | 
				
			||||||
    Align, CentralPanel, Checkbox, Color32, ColorImage, Context, Image, ScrollArea, Slider,
 | 
					    Align, CentralPanel, Checkbox, Color32, Context, Image, ScrollArea, Slider, TextEdit,
 | 
				
			||||||
    TextEdit, TextureOptions, Ui, ViewportBuilder, ViewportId,
 | 
					    TextureOptions, Ui, ViewportBuilder, ViewportId,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
 | 
					use egui_extras::{Column, Size, StripBuilder, TableBuilder};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    emulator::SimId,
 | 
					    emulator::SimId,
 | 
				
			||||||
    memory::{MemoryMonitor, MemoryView},
 | 
					    memory::{MemoryMonitor, MemoryView},
 | 
				
			||||||
    vram::{VramImageLoader, VramResource as _, VramTextureLoader},
 | 
					    vram::{VramImage, VramImageLoader, VramResource as _, VramTextureLoader},
 | 
				
			||||||
    window::{utils::UiExt, AppWindow},
 | 
					    window::{utils::UiExt, AppWindow},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -242,7 +242,7 @@ impl BgMapLoader {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn load_bgmap(&self, bgmap_index: usize, generic_palette: bool) -> Option<ColorImage> {
 | 
					    fn update_bgmap(&self, image: &mut VramImage, bgmap_index: usize, generic_palette: bool) {
 | 
				
			||||||
        let chardata = self.chardata.borrow();
 | 
					        let chardata = self.chardata.borrow();
 | 
				
			||||||
        let bgmaps = self.bgmaps.borrow();
 | 
					        let bgmaps = self.bgmaps.borrow();
 | 
				
			||||||
        let brightness = self.brightness.borrow();
 | 
					        let brightness = self.brightness.borrow();
 | 
				
			||||||
| 
						 | 
					@ -265,7 +265,6 @@ impl BgMapLoader {
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut data = vec![0u8; 512 * 512];
 | 
					 | 
				
			||||||
        for (i, cell) in bgmaps
 | 
					        for (i, cell) in bgmaps
 | 
				
			||||||
            .range::<u16>(bgmap_index * 4096, 4096)
 | 
					            .range::<u16>(bgmap_index * 4096, 4096)
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
| 
						 | 
					@ -275,21 +274,17 @@ impl BgMapLoader {
 | 
				
			||||||
            let char = chardata.range::<u16>(char_index * 8, 8);
 | 
					            let char = chardata.range::<u16>(char_index * 8, 8);
 | 
				
			||||||
            let palette = &colors[palette_index];
 | 
					            let palette = &colors[palette_index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let mut target_idx = (i % 64) * 8 + (i / 64) * 8 * 512;
 | 
					 | 
				
			||||||
            for row in 0..8 {
 | 
					            for row in 0..8 {
 | 
				
			||||||
                let dests = &mut data[target_idx..target_idx + 8];
 | 
					                let y = row + (i / 64) * 8;
 | 
				
			||||||
                let pixels = self.read_char_row(char, hflip, vflip, row);
 | 
					                for (col, pixel) in self.read_char_row(char, hflip, vflip, row).enumerate() {
 | 
				
			||||||
                for (dest, pixel) in dests.iter_mut().zip(pixels) {
 | 
					                    let x = col + (i % 64) * 8;
 | 
				
			||||||
                    *dest = palette[pixel as usize];
 | 
					                    image.write((x, y), palette[pixel as usize]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                target_idx += 512;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        Some(ColorImage::from_gray([512, 512], &data))
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn load_bgmap_cell(&self, index: usize, generic_palette: bool) -> Option<ColorImage> {
 | 
					    fn update_bgmap_cell(&self, image: &mut VramImage, index: usize, generic_palette: bool) {
 | 
				
			||||||
        let chardata = self.chardata.borrow();
 | 
					        let chardata = self.chardata.borrow();
 | 
				
			||||||
        let bgmaps = self.bgmaps.borrow();
 | 
					        let bgmaps = self.bgmaps.borrow();
 | 
				
			||||||
        let brightness = self.brightness.borrow();
 | 
					        let brightness = self.brightness.borrow();
 | 
				
			||||||
| 
						 | 
					@ -297,7 +292,6 @@ impl BgMapLoader {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let brts = brightness.range::<u8>(0, 8);
 | 
					        let brts = brightness.range::<u8>(0, 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut data = vec![0u8; 8 * 8];
 | 
					 | 
				
			||||||
        let cell = bgmaps.read::<u16>(index);
 | 
					        let cell = bgmaps.read::<u16>(index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let (char_index, vflip, hflip, palette_index) = parse_cell(cell);
 | 
					        let (char_index, vflip, hflip, palette_index) = parse_cell(cell);
 | 
				
			||||||
| 
						 | 
					@ -308,17 +302,11 @@ impl BgMapLoader {
 | 
				
			||||||
            parse_palette(palettes.read(palette_index * 2), brts)
 | 
					            parse_palette(palettes.read(palette_index * 2), brts)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut target_idx = 0;
 | 
					 | 
				
			||||||
        for row in 0..8 {
 | 
					        for row in 0..8 {
 | 
				
			||||||
            let dests = &mut data[target_idx..target_idx + 8];
 | 
					            for (col, pixel) in self.read_char_row(char, hflip, vflip, row).enumerate() {
 | 
				
			||||||
            let pixels = self.read_char_row(char, hflip, vflip, row);
 | 
					                image.write((col, row), palette[pixel as usize]);
 | 
				
			||||||
            for (dest, pixel) in dests.iter_mut().zip(pixels) {
 | 
					 | 
				
			||||||
                *dest = palette[pixel as usize];
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            target_idx += 8;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        Some(ColorImage::from_gray([8, 8], &data))
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn read_char_row(
 | 
					    fn read_char_row(
 | 
				
			||||||
| 
						 | 
					@ -343,24 +331,42 @@ impl VramImageLoader for BgMapLoader {
 | 
				
			||||||
        concat!(module_path!(), "::BgMapLoader")
 | 
					        concat!(module_path!(), "::BgMapLoader")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn add(&self, resource: &Self::Resource) -> Option<ColorImage> {
 | 
					    fn add(&self, resource: &Self::Resource) -> Option<VramImage> {
 | 
				
			||||||
        match resource {
 | 
					        match resource {
 | 
				
			||||||
            BgMapResource::BgMap {
 | 
					            BgMapResource::BgMap {
 | 
				
			||||||
                index,
 | 
					                index,
 | 
				
			||||||
                generic_palette,
 | 
					                generic_palette,
 | 
				
			||||||
            } => self.load_bgmap(*index, *generic_palette),
 | 
					            } => {
 | 
				
			||||||
 | 
					                let mut image = VramImage::new(64 * 8, 64 * 8);
 | 
				
			||||||
 | 
					                self.update_bgmap(&mut image, *index, *generic_palette);
 | 
				
			||||||
 | 
					                Some(image)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            BgMapResource::Cell {
 | 
					            BgMapResource::Cell {
 | 
				
			||||||
                index,
 | 
					                index,
 | 
				
			||||||
                generic_palette,
 | 
					                generic_palette,
 | 
				
			||||||
            } => self.load_bgmap_cell(*index, *generic_palette),
 | 
					            } => {
 | 
				
			||||||
 | 
					                let mut image = VramImage::new(8, 8);
 | 
				
			||||||
 | 
					                self.update_bgmap_cell(&mut image, *index, *generic_palette);
 | 
				
			||||||
 | 
					                Some(image)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn update<'a>(
 | 
					    fn update<'a>(
 | 
				
			||||||
        &'a self,
 | 
					        &'a self,
 | 
				
			||||||
        resources: impl Iterator<Item = &'a Self::Resource>,
 | 
					        resources: impl Iterator<Item = (&'a Self::Resource, &'a mut VramImage)>,
 | 
				
			||||||
    ) -> Vec<(&'a Self::Resource, ColorImage)> {
 | 
					    ) {
 | 
				
			||||||
        let _ = resources;
 | 
					        for (resource, image) in resources {
 | 
				
			||||||
        vec![]
 | 
					            match resource {
 | 
				
			||||||
 | 
					                BgMapResource::BgMap {
 | 
				
			||||||
 | 
					                    index,
 | 
				
			||||||
 | 
					                    generic_palette,
 | 
				
			||||||
 | 
					                } => self.update_bgmap(image, *index, *generic_palette),
 | 
				
			||||||
 | 
					                BgMapResource::Cell {
 | 
				
			||||||
 | 
					                    index,
 | 
				
			||||||
 | 
					                    generic_palette,
 | 
				
			||||||
 | 
					                } => self.update_bgmap_cell(image, *index, *generic_palette),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
use std::{fmt::Display, sync::Arc};
 | 
					use std::{fmt::Display, sync::Arc};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use egui::{
 | 
					use egui::{
 | 
				
			||||||
    Align, CentralPanel, Color32, ColorImage, ComboBox, Context, Image, ScrollArea, Slider,
 | 
					    Align, CentralPanel, Color32, ComboBox, Context, Image, ScrollArea, Slider, TextEdit,
 | 
				
			||||||
    TextEdit, TextureOptions, Ui, Vec2, ViewportBuilder, ViewportId,
 | 
					    TextureOptions, Ui, Vec2, ViewportBuilder, ViewportId,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
 | 
					use egui_extras::{Column, Size, StripBuilder, TableBuilder};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    emulator::SimId,
 | 
					    emulator::SimId,
 | 
				
			||||||
    memory::{MemoryMonitor, MemoryView},
 | 
					    memory::{MemoryMonitor, MemoryView},
 | 
				
			||||||
    vram::{VramImageLoader, VramResource as _, VramTextureLoader},
 | 
					    vram::{VramImage, VramImageLoader, VramResource as _, VramTextureLoader},
 | 
				
			||||||
    window::{utils::UiExt as _, AppWindow},
 | 
					    window::{utils::UiExt as _, AppWindow},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -294,38 +294,34 @@ impl CharDataLoader {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn load_character(&self, palette: VramPalette, index: usize) -> Option<ColorImage> {
 | 
					    fn update_character(&self, image: &mut VramImage, palette: VramPalette, index: usize) {
 | 
				
			||||||
        if index >= 2048 {
 | 
					        if index >= 2048 {
 | 
				
			||||||
            return None;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let palette = self.load_palette(palette);
 | 
					        let palette = self.load_palette(palette);
 | 
				
			||||||
        let chardata = self.chardata.borrow();
 | 
					        let chardata = self.chardata.borrow();
 | 
				
			||||||
        let character = chardata.range::<u16>(index * 8, 8);
 | 
					        let character = chardata.range::<u16>(index * 8, 8);
 | 
				
			||||||
        let mut buffer = Vec::with_capacity(8 * 8);
 | 
					        for (row, pixels) in character.iter().enumerate() {
 | 
				
			||||||
        for row in character {
 | 
					            for col in 0..8 {
 | 
				
			||||||
            for offset in (0..16).step_by(2) {
 | 
					                let char = (pixels >> (col * 2)) & 0x03;
 | 
				
			||||||
                let char = (row >> offset) & 0x3;
 | 
					                image.write((col, row), palette[char as usize]);
 | 
				
			||||||
                buffer.push(palette[char as usize]);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Some(ColorImage::from_gray([8, 8], &buffer))
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn load_character_data(&self, palette: VramPalette) -> Option<ColorImage> {
 | 
					    fn update_character_data(&self, image: &mut VramImage, palette: VramPalette) {
 | 
				
			||||||
        let palette = self.load_palette(palette);
 | 
					        let palette = self.load_palette(palette);
 | 
				
			||||||
        let chardata = self.chardata.borrow();
 | 
					        let chardata = self.chardata.borrow();
 | 
				
			||||||
        let mut buffer = vec![0; 8 * 8 * 2048];
 | 
					        for (row, pixels) in chardata.range::<u16>(0, 8 * 2048).iter().enumerate() {
 | 
				
			||||||
        for (i, row) in chardata.range::<u16>(0, 8 * 2048).iter().enumerate() {
 | 
					            let char_index = row / 8;
 | 
				
			||||||
            let bytes =
 | 
					            let row_index = row % 8;
 | 
				
			||||||
                [0, 2, 4, 6, 8, 10, 12, 14].map(|off| palette[(*row as usize >> off) & 0x3]);
 | 
					 | 
				
			||||||
            let char_index = i / 8;
 | 
					 | 
				
			||||||
            let row_index = i % 8;
 | 
					 | 
				
			||||||
            let x = (char_index % 16) * 8;
 | 
					            let x = (char_index % 16) * 8;
 | 
				
			||||||
            let y = (char_index / 16) * 8 + row_index;
 | 
					            let y = (char_index / 16) * 8 + row_index;
 | 
				
			||||||
            let write_index = (y * 16 * 8) + x;
 | 
					            for col in 0..8 {
 | 
				
			||||||
            buffer[write_index..write_index + 8].copy_from_slice(&bytes);
 | 
					                let char = (pixels >> (col * 2)) & 0x03;
 | 
				
			||||||
 | 
					                image.write((x + col, y), palette[char as usize]);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Some(ColorImage::from_gray([8 * 16, 8 * 128], &buffer))
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn load_palette(&self, palette: VramPalette) -> [u8; 4] {
 | 
					    fn load_palette(&self, palette: VramPalette) -> [u8; 4] {
 | 
				
			||||||
| 
						 | 
					@ -346,18 +342,34 @@ impl VramImageLoader for CharDataLoader {
 | 
				
			||||||
        concat!(module_path!(), "::CharDataLoader")
 | 
					        concat!(module_path!(), "::CharDataLoader")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn add(&self, resource: &Self::Resource) -> Option<ColorImage> {
 | 
					    fn add(&self, resource: &Self::Resource) -> Option<VramImage> {
 | 
				
			||||||
        match resource {
 | 
					        match resource {
 | 
				
			||||||
            CharDataResource::Character { palette, index } => self.load_character(*palette, *index),
 | 
					            CharDataResource::Character { palette, index } => {
 | 
				
			||||||
            CharDataResource::CharacterData { palette } => self.load_character_data(*palette),
 | 
					                let mut image = VramImage::new(8, 8);
 | 
				
			||||||
 | 
					                self.update_character(&mut image, *palette, *index);
 | 
				
			||||||
 | 
					                Some(image)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            CharDataResource::CharacterData { palette } => {
 | 
				
			||||||
 | 
					                let mut image = VramImage::new(8 * 16, 8 * 128);
 | 
				
			||||||
 | 
					                self.update_character_data(&mut image, *palette);
 | 
				
			||||||
 | 
					                Some(image)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn update<'a>(
 | 
					    fn update<'a>(
 | 
				
			||||||
        &'a self,
 | 
					        &'a self,
 | 
				
			||||||
        resources: impl Iterator<Item = &'a Self::Resource>,
 | 
					        resources: impl Iterator<Item = (&'a Self::Resource, &'a mut VramImage)>,
 | 
				
			||||||
    ) -> Vec<(&'a Self::Resource, ColorImage)> {
 | 
					    ) {
 | 
				
			||||||
        let _ = resources;
 | 
					        for (resource, image) in resources {
 | 
				
			||||||
        vec![]
 | 
					            match resource {
 | 
				
			||||||
 | 
					                CharDataResource::Character { palette, index } => {
 | 
				
			||||||
 | 
					                    self.update_character(image, *palette, *index)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                CharDataResource::CharacterData { palette } => {
 | 
				
			||||||
 | 
					                    self.update_character_data(image, *palette)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue