mocari 0.2.4

A pure Rust Live2D/Cubism-compatible runtime
Documentation
use crate::{Error, Result};

use super::{Moc3Header, Moc3SectionOffsets, parse::read_f32};

const CANVAS_INFO_SIZE: usize = 64;
const F32_SIZE: usize = 4;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Moc3CanvasInfo {
    pixels_per_unit: f32,
    origin_x: f32,
    origin_y: f32,
    width: f32,
    height: f32,
    flags: u8,
}

impl Moc3CanvasInfo {
    pub fn parse(bytes: &[u8]) -> Result<Self> {
        let header = Moc3Header::parse(bytes)?;
        let offsets = Moc3SectionOffsets::parse(bytes)?;
        let offset = usize::try_from(offsets.canvas_info_offset())
            .map_err(|_| invalid_canvas("canvas info offset does not fit in platform usize"))?;

        if bytes.len().saturating_sub(offset) < CANVAS_INFO_SIZE {
            return Err(invalid_canvas("canvas info is incomplete"));
        }

        Ok(Self {
            pixels_per_unit: read_f32(bytes, offset, header.endianness()),
            origin_x: read_f32(bytes, offset + F32_SIZE, header.endianness()),
            origin_y: read_f32(bytes, offset + F32_SIZE * 2, header.endianness()),
            width: read_f32(bytes, offset + F32_SIZE * 3, header.endianness()),
            height: read_f32(bytes, offset + F32_SIZE * 4, header.endianness()),
            flags: bytes[offset + F32_SIZE * 5],
        })
    }

    pub fn pixels_per_unit(&self) -> f32 {
        self.pixels_per_unit
    }

    pub fn origin_x(&self) -> f32 {
        self.origin_x
    }

    pub fn origin_y(&self) -> f32 {
        self.origin_y
    }

    pub fn width(&self) -> f32 {
        self.width
    }

    pub fn height(&self) -> f32 {
        self.height
    }

    pub fn reverse_y_coordinate(&self) -> bool {
        self.flags & 1 == 1
    }
}

fn invalid_canvas(message: impl Into<String>) -> Error {
    Error::InvalidMoc3 {
        message: message.into(),
    }
}