2026-07-25 12:39:32 +02:00
|
|
|
|
internal import CPlaydate
|
|
|
|
|
|
|
|
|
|
|
|
extension Graphics {
|
2026-09-18 13:15:08 +00:00
|
|
|
|
/// An image table. Wraps `LCDBitmapTable`. Its bitmaps are borrowed and invalid once
|
|
|
|
|
|
/// the table is freed.
|
2026-07-25 12:39:32 +02:00
|
|
|
|
public final class BitmapTable {
|
|
|
|
|
|
let pointer: OpaquePointer
|
|
|
|
|
|
|
|
|
|
|
|
init(pointer: OpaquePointer) {
|
|
|
|
|
|
self.pointer = pointer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-18 13:15:08 +00:00
|
|
|
|
/// Room for `count` bitmaps of `width` × `height` pixels.
|
2026-07-25 12:39:32 +02:00
|
|
|
|
public convenience init(count: Int, width: Int, height: Int) {
|
|
|
|
|
|
let pointer = gfx.pointee.newBitmapTable.unsafelyUnwrapped(Int32(count), Int32(width), Int32(height))
|
|
|
|
|
|
self.init(pointer: pointer.unsafelyUnwrapped)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public convenience init(path: String) throws(PlaydateError) {
|
|
|
|
|
|
var error: UnsafePointer<CChar>?
|
2026-09-18 13:15:08 +00:00
|
|
|
|
let pointer = path.withCString { gfx.pointee.loadBitmapTable.unsafelyUnwrapped($0, &error) }
|
2026-07-25 12:39:32 +02:00
|
|
|
|
guard let pointer else { throw PlaydateError(cString: error) }
|
|
|
|
|
|
self.init(pointer: pointer)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
deinit {
|
|
|
|
|
|
gfx.pointee.freeBitmapTable.unsafelyUnwrapped(pointer)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func load(path: String) throws(PlaydateError) {
|
|
|
|
|
|
var error: UnsafePointer<CChar>?
|
2026-09-18 13:15:08 +00:00
|
|
|
|
path.withCString { gfx.pointee.loadIntoBitmapTable.unsafelyUnwrapped($0, pointer, &error) }
|
2026-07-25 12:39:32 +02:00
|
|
|
|
if let error { throw PlaydateError(cString: error) }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-18 13:15:08 +00:00
|
|
|
|
/// `nil` if out of range.
|
2026-07-25 12:39:32 +02:00
|
|
|
|
public func bitmap(at index: Int) -> Bitmap? {
|
|
|
|
|
|
guard let bitmap = gfx.pointee.getTableBitmap.unsafelyUnwrapped(pointer, Int32(index)) else {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return Bitmap(pointer: bitmap, isOwned: false)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-18 13:15:08 +00:00
|
|
|
|
/// Bitmap count and cells across the source image.
|
2026-07-25 12:39:32 +02:00
|
|
|
|
public var info: (count: Int, cellsWide: Int) {
|
|
|
|
|
|
var count: Int32 = 0, width: Int32 = 0
|
|
|
|
|
|
gfx.pointee.getBitmapTableInfo.unsafelyUnwrapped(pointer, &count, &width)
|
|
|
|
|
|
return (Int(count), Int(width))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public var count: Int { info.count }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-07-26 00:31:58 +02:00
|
|
|
|
|
|
|
|
|
|
extension Graphics.BitmapTable: RandomAccessCollection {
|
|
|
|
|
|
public var startIndex: Int { 0 }
|
|
|
|
|
|
public var endIndex: Int { count }
|
|
|
|
|
|
|
2026-09-18 13:15:08 +00:00
|
|
|
|
/// Traps if out of range.
|
2026-07-26 00:31:58 +02:00
|
|
|
|
public subscript(position: Int) -> Graphics.Bitmap {
|
|
|
|
|
|
guard let bitmap = bitmap(at: position) else {
|
|
|
|
|
|
preconditionFailure("bitmap table index out of range")
|
|
|
|
|
|
}
|
|
|
|
|
|
return bitmap
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|