swizzleinator 0.2.1

Texture swizzling/deswizzling library
Documentation
use super::{Deswizzler, Format, SwizzleError, Swizzler};

pub struct Ps3;

impl Swizzler for Ps3 {
    fn swizzle<T: Format>(
        source: &mut [u8],
        dest: &mut [u8],
        dimensions: (usize, usize, usize),
        format: T,
        align_resolution: bool,
    ) -> Result<(), SwizzleError> {
        ps3::do_swizzle(source, dest, dimensions, format, false, align_resolution);
        Ok(())
    }
}

impl Deswizzler for Ps3 {
    fn deswizzle<T: Format>(
        source: &mut [u8],
        dest: &mut [u8],
        dimensions: (usize, usize, usize),
        format: T,
        align_resolution: bool,
    ) -> Result<(), SwizzleError> {
        ps3::do_swizzle(source, dest, dimensions, format, true, align_resolution);
        Ok(())
    }
}

mod ps3 {
    use crate::swizzle::{Format, SwizzleError};

    pub fn do_swizzle<T: Format>(
        source: &mut [u8],
        dest: &mut [u8],
        dimensions: (usize, usize, usize),
        format: T,
        unswizzle: bool,
        align_resolution: bool,
    ) {
        let (width, height, depth) = dimensions;
        let pixel_block_size = format.pixel_block_size();
        let block_size = format.block_size();

        let (width_src, height_src) = if align_resolution && format.is_compressed() {
            (width.next_power_of_two(), height.next_power_of_two())
        } else {
            (width, height)
        };

        let width_texels = width_src / pixel_block_size;
        let height_texels = height_src / pixel_block_size;

        let mut data_index = 0;

        let texel_size = width_texels * height_texels;

        for z in 0..depth {
            let slice_dest = &mut dest[(z * width * height * format.bpp()) / 8..];

            for t in 0..texel_size {
                let pixel_index = crate::swizzle::morton(t, width_texels, height_texels);
                let dest_index = block_size * pixel_index;
                let (src, dst) = if unswizzle {
                    (data_index, dest_index)
                } else {
                    (dest_index, data_index)
                };

                if (src + block_size) <= source.len() && (dst + block_size) <= slice_dest.len() {
                    slice_dest[dst..dst + block_size]
                        .copy_from_slice(&source[src..src + block_size]);
                }

                data_index += block_size;
            }
        }
    }
}

pub struct Ps4;

impl Swizzler for Ps4 {
    fn swizzle<T: Format>(
        source: &mut [u8],
        dest: &mut [u8],
        dimensions: (usize, usize, usize),
        format: T,
        align_resolution: bool,
    ) -> Result<(), SwizzleError> {
        ps4::do_swizzle(source, dest, dimensions, format, false, align_resolution);
        Ok(())
    }
}

impl Deswizzler for Ps4 {
    fn deswizzle<T: Format>(
        source: &mut [u8],
        dest: &mut [u8],
        dimensions: (usize, usize, usize),
        format: T,
        align_resolution: bool,
    ) -> Result<(), SwizzleError> {
        ps4::do_swizzle(source, dest, dimensions, format, true, align_resolution);
        Ok(())
    }
}

mod ps4 {
    use crate::swizzle::Format;

    pub fn do_swizzle<T: Format>(
        source: &mut [u8],
        dest: &mut [u8],
        dimensions: (usize, usize, usize),
        format: T,
        unswizzle: bool,
        align_resolution: bool,
    ) {
        let (width, height, depth) = dimensions;
        let pixel_block_size = format.pixel_block_size();
        let block_size = format.block_size();

        let (width_src, height_src) = if align_resolution && format.is_compressed() {
            (width.next_power_of_two(), height.next_power_of_two())
        } else {
            (width, height)
        };

        let width_texels_dest = width / pixel_block_size;
        let height_texels_dest = height / pixel_block_size;

        let width_texels = width_src / pixel_block_size;
        let width_texels_aligned = width_texels.div_ceil(8);
        let height_texels = height_src / pixel_block_size;
        let height_texels_aligned = height_texels.div_ceil(8);
        let mut data_index = 0;

        for z in 0..depth {
            let slice_dest = &mut dest[(z * width * height * format.bpp()) / 8..];

            for y in 0..height_texels_aligned {
                for x in 0..width_texels_aligned {
                    for t in 0..64 {
                        let pixel_index = crate::swizzle::morton(t, 8, 8);
                        let div = pixel_index / 8;
                        let rem = pixel_index % 8;
                        let x_offset = (x * 8) + rem;
                        let y_offset = (y * 8) + div;

                        if x_offset < width_texels_dest && y_offset < height_texels_dest {
                            let dest_pixel_index = y_offset * width_texels_dest + x_offset;
                            let dest_index = block_size * dest_pixel_index;
                            let (src, dst) = if unswizzle {
                                (data_index, dest_index)
                            } else {
                                (dest_index, data_index)
                            };

                            if (src + block_size) <= source.len()
                                && (dst + block_size) <= slice_dest.len()
                            {
                                slice_dest[dst..dst + block_size]
                                    .copy_from_slice(&source[src..src + block_size]);
                            }
                        }

                        data_index += block_size;
                    }
                }
            }
        }
    }
}