etagere 0.3.0

Dynamic 2D texture atlas allocation using the shelf packing algorithm.
Documentation
use crate::{AtlasAllocator, size2};
use alloc::boxed::Box;

/// 1 means OK, 0 means error.
pub type EtagereStatus = u32;
pub type EtagereAllocationId = u32;


#[repr(C)]
pub struct EtagereAllocation {
    pub rectangle: EtagereRectangle,
    pub id: EtagereAllocationId,
}

#[repr(C)]
pub struct EtagereRectangle {
    pub min_x: i32,
    pub min_y: i32,
    pub max_x: i32,
    pub max_y: i32,
}


#[repr(C)]
pub struct EtagereAllocatorOptions {
    pub width_alignment: i32,
    pub height_alignment: i32,
    pub num_columns: i32,
    pub flags: u32,
}

pub const ETAGERE_FLAGS_VERTICAL_SHELVES: u32 = 1;

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_new(width: i32, height: i32) -> *mut AtlasAllocator {
    Box::into_raw(Box::new(AtlasAllocator::new(size2(width, height))))
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_with_options(
    width: i32,
    height: i32,
    options: &EtagereAllocatorOptions
) -> *mut AtlasAllocator {
    let options = crate::AllocatorOptions {
        alignment: size2(options.width_alignment, options.height_alignment),
        num_columns: options.num_columns,
        vertical_shelves: (options.flags & ETAGERE_FLAGS_VERTICAL_SHELVES) != 0,
    };
    Box::into_raw(Box::new(AtlasAllocator::with_options(size2(width, height), &options)))
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_delete(allocator: *mut AtlasAllocator)  {
    let _ = Box::from_raw(allocator);
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_allocate(allocator: &mut AtlasAllocator, width: i32, height: i32, allocation: &mut EtagereAllocation) -> EtagereStatus {
    match allocator.allocate(size2(width, height)) {
        Some(alloc) => {
            allocation.id = alloc.id.serialize();
            allocation.rectangle.min_x = alloc.rectangle.min.x;
            allocation.rectangle.min_y = alloc.rectangle.min.y;
            allocation.rectangle.max_x = alloc.rectangle.max.x;
            allocation.rectangle.max_y = alloc.rectangle.max.y;
            return 1;
        }
        None => {
            allocation.id = core::u32::MAX;
            allocation.rectangle.min_x = 0;
            allocation.rectangle.min_y = 0;
            allocation.rectangle.max_x = 0;
            allocation.rectangle.max_y = 0;
            return 0;
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_deallocate(allocator: &mut AtlasAllocator, id: EtagereAllocationId) {
    allocator.deallocate(crate::AllocId::deserialize(id));
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_clear(allocator: &mut AtlasAllocator) {
    allocator.clear();
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_allocated_space(allocator: &AtlasAllocator) -> i32 {
    allocator.allocated_space()
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_free_space(allocator: &AtlasAllocator) -> i32 {
    allocator.free_space()
}

#[no_mangle]
pub unsafe extern "C" fn etagere_atlas_allocator_get(allocator: &AtlasAllocator, id: EtagereAllocationId) -> EtagereRectangle {
    let rect = allocator.get(crate::AllocId::deserialize(id));
    return EtagereRectangle {
        min_x: rect.min.x,
        min_y: rect.min.y,
        max_x: rect.max.x,
        max_y: rect.max.y,
    };
}

//use core::ffi::c_char;
//#[no_mangle]
//pub unsafe extern "C" fn etagere_atlas_allocator_dump_svg(allocator: &AtlasAllocator, file_name: *const c_char) -> EtagereStatus {
//    let cstr = core::ffi::CStr::from_ptr(file_name);
//    let rstr = String::from_utf8_lossy(cstr.to_bytes());
//    let mut file = match core::fs::File::create(rstr.as_ref()) {
//        Ok(file) => file,
//        Err(..) => {
//            return 0;
//        }
//    };
//
//    match allocator.dump_svg(&mut file) {
//        Ok(..) => 1,
//        Err(..) => 0,
//    }
//}