libgm 0.5.1

A tool for modding, unpacking and decompiling GameMaker games
Documentation
use std::fmt;

use macros::num_enum;

use crate::prelude::*;
use crate::util::init::num_enum_from;
use crate::wad::deserialize::reader::DataReader;
use crate::wad::elements::GMElement;
use crate::wad::serialize::builder::DataBuilder;

#[derive(Debug, Clone, PartialEq)]
pub struct Data {
    pub bitmap_type: Type,
    pub width: i32,
    pub height: i32,
    pub ver_data: VersionData,
}

#[num_enum(i32)]
pub enum Type {
    TypeJPEGNoHeader,
    TypeJPEG,
    TypeJPEGWithAlpha,
    TypePNG,
    TypeGIF,
    TypeLossless8bit,
    TypeLossless15bit,
    TypeLossless24bit,
    TypeLossless8bitA,
    TypeLossless32bit,
}

impl GMElement for Data {
    fn deserialize(reader: &mut DataReader) -> Result<Self> {
        let bitmap_type: Type = num_enum_from(reader.read_i32()?)?;
        let width = reader.read_i32()?;
        let height = reader.read_i32()?;

        let ver_data = if reader.general_info.is_version_at_least((2022, 1)) {
            let tpe_index = reader.read_i32()?;
            VersionData::Post2022_1(VersionDataPost2022_1 { tpe_index })
        } else {
            let image_data_length = reader.read_count("YYSWF Bitmap Image Data")?;
            let alpha_data_length = reader.read_count("YYSWF Bitmap Alpha Data")?;
            let color_palette_data_length = reader.read_count("YYSWF Bitmap Color Palette Data")?;

            let image_data: Vec<u8> = reader
                .read_bytes_dyn(image_data_length)
                .context("reading Image Data of Bitmap Data")?
                .to_vec();
            let alpha_data: Vec<u8> = reader
                .read_bytes_dyn(alpha_data_length)
                .context("reading Alpha Data of Bitmap Data")?
                .to_vec();
            let color_palette_data: Vec<u8> = reader
                .read_bytes_dyn(color_palette_data_length)
                .context("reading Color Palette Data of Bitmap Data")?
                .to_vec();

            reader.align(4)?;
            VersionData::Pre2022_1(VersionDataPre2022_1 {
                image_data,
                alpha_data,
                color_palette_data,
            })
        };

        Ok(Self { bitmap_type, width, height, ver_data })
    }

    fn serialize(&self, builder: &mut DataBuilder) -> Result<()> {
        builder.write_i32(self.bitmap_type.into());
        builder.write_i32(self.width);
        builder.write_i32(self.height);
        if builder.is_version_at_least((2022, 1)) {
            if let VersionData::Post2022_1(ref data) = self.ver_data {
                builder.write_i32(data.tpe_index);
            } else {
                bail!("Sprite YYSWF Bitmap Data: TPE Index not set in Post 2022.1+");
            }
        } else if let VersionData::Pre2022_1(ref data) = self.ver_data {
            builder.write_usize(data.image_data.len())?;
            builder.write_usize(data.alpha_data.len())?;
            builder.write_usize(data.color_palette_data.len())?;
            builder.write_bytes(&data.image_data);
            builder.write_bytes(&data.alpha_data);
            builder.write_bytes(&data.color_palette_data);
            builder.align(4);
        } else {
            bail!("Sprite YYSWF Bitmap Data: version specific data not set in Pre 2022.1+");
        }
        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum VersionData {
    Pre2022_1(VersionDataPre2022_1),
    Post2022_1(VersionDataPost2022_1),
}

#[derive(Clone, PartialEq)]
pub struct VersionDataPre2022_1 {
    pub image_data: Vec<u8>,
    pub alpha_data: Vec<u8>,
    pub color_palette_data: Vec<u8>,
}

impl fmt::Debug for VersionDataPre2022_1 {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("VersionDataPre2022_1")
            .finish_non_exhaustive()
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct VersionDataPost2022_1 {
    pub tpe_index: i32,
}