From c4e0a1125993a14cce3edfdf8c0508673fa47e65 Mon Sep 17 00:00:00 2001 From: gered Date: Wed, 20 Jul 2022 16:32:19 -0400 Subject: [PATCH] add loading and saving support to BlendMap --- libretrogd/src/graphics/blendmap.rs | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/libretrogd/src/graphics/blendmap.rs b/libretrogd/src/graphics/blendmap.rs index 8bcca2d..4e78513 100644 --- a/libretrogd/src/graphics/blendmap.rs +++ b/libretrogd/src/graphics/blendmap.rs @@ -1,12 +1,24 @@ +use std::fs::File; +use std::io::{BufReader, BufWriter}; +use std::path::Path; + +use byteorder::{ReadBytesExt, WriteBytesExt}; use thiserror::Error; use crate::graphics::*; use crate::math::*; +use crate::utils::bytes::ReadFixedLengthByteArray; #[derive(Error, Debug)] pub enum BlendMapError { #[error("Source color {0} is out of range for this BlendMap")] InvalidSourceColor(u8), + + #[error("Bad or unsupported BlendMap file: {0}")] + BadFile(String), + + #[error("BlendMap I/O error")] + IOError(#[from] std::io::Error), } /// A lookup table used by [`BlendMap`]s. This table stores destination color to blend color @@ -226,11 +238,57 @@ impl BlendMap { None } } + + pub fn load_from_file(path: &Path) -> Result { + let f = File::open(path)?; + let mut reader = BufReader::new(f); + Self::load_from_bytes(&mut reader) + } + + pub fn load_from_bytes(reader: &mut T) -> Result { + let ident: [u8; 4] = reader.read_bytes()?; + if ident != *b"BMap" { + return Err(BlendMapError::BadFile(String::from("Unrecognized header"))); + } + + let start_color = reader.read_u8()?; + let end_color = reader.read_u8()?; + let num_maps = (end_color - start_color + 1) as usize; + + let mut maps = Vec::with_capacity(num_maps); + for _ in 0..num_maps { + let map: BlendMapping = reader.read_bytes()?; + maps.push(map); + } + + Ok(BlendMap { + start_color, + end_color, + mapping: maps.into_boxed_slice() + }) + } + + pub fn to_file(&self, path: &Path) -> Result<(), BlendMapError> { + let f = File::create(path)?; + let mut writer = BufWriter::new(f); + self.to_bytes(&mut writer) + } + + pub fn to_bytes(&self, writer: &mut T) -> Result<(), BlendMapError> { + writer.write_all(b"BMap")?; + writer.write_u8(self.start_color)?; + writer.write_u8(self.end_color)?; + for map in self.mapping.iter() { + writer.write_all(map)?; + } + Ok(()) + } } #[cfg(test)] mod tests { use claim::*; + use tempfile::TempDir; use super::*; @@ -324,6 +382,25 @@ mod tests { ); + Ok(()) + } + + #[test] + fn load_and_save() -> Result<(), BlendMapError> { + let tmp_dir = TempDir::new()?; + + let mut blend_map = BlendMap::new(2, 3); + for i in 0..=255 { + blend_map.set_mapping(2, i, i)?; + blend_map.set_mapping(3, i, 255 - i)?; + } + + let save_path = tmp_dir.path().join("test_blend_map.blendmap"); + blend_map.to_file(&save_path)?; + + let loaded_blend_map = BlendMap::load_from_file(&save_path)?; + assert!(blend_map == loaded_blend_map, "loaded BlendMap is not the same as the original"); + Ok(()) } } \ No newline at end of file