forked from AbleOS/ableos
koniifer
6a8d92d2c2
refactor image loader for multiple filetypes port some broken math stuff make logger more readable
101 lines
2.2 KiB
Plaintext
101 lines
2.2 KiB
Plaintext
.{Color, Surface, new_surface} := @use("../lib.hb");
|
|
.{log, memory} := @use("../../../stn/src/lib.hb")
|
|
|
|
/* source:
|
|
https://github.com/phoboslab/qoi/blob/master/qoi.h */
|
|
|
|
QOI_SRGB := 0
|
|
QOI_LINEAR := 1
|
|
QOI_OP_INDEX := 0x0
|
|
QOI_OP_DIFF := 0x40
|
|
QOI_OP_LUMA := 0x80
|
|
QOI_OP_RUN := 0xC0
|
|
QOI_OP_RGB := 0xFE
|
|
QOI_OP_RGBA := 0xFF
|
|
QOI_MASK_2 := 0xC0
|
|
QOI_COLOR_HASH := fn(c: Color): u8 {
|
|
return (c.r * 3 + c.g * 5 + c.b * 7 + c.a * 11) % 64
|
|
}
|
|
QOI_MAGIC := 0x716F6966
|
|
QOI_PIXELS_MAX := 400000000
|
|
|
|
QuiteOkayHeader := packed struct {
|
|
magic: u32,
|
|
width: u32,
|
|
height: u32,
|
|
channels: u8,
|
|
colorspace: u8,
|
|
}
|
|
|
|
be_to_le := fn(big: u32): u32 {
|
|
return (big & 0xFF000000) >> 24 | (big & 0xFF0000) >> 8 | (big & 0xFF00) << 8 | (big & 0xFF) << 24
|
|
}
|
|
|
|
from := fn(qoi: ^u8): ?Surface {
|
|
header := @as(^QuiteOkayHeader, @bitcast(qoi))
|
|
|
|
qoi += @sizeof(QuiteOkayHeader)
|
|
|
|
width := be_to_le(header.width)
|
|
height := be_to_le(header.height)
|
|
|
|
if be_to_le(header.magic) != QOI_MAGIC | width == 0 | height == 0 | header.channels < 3 | header.channels > 4 {
|
|
log.error("Invalid QOI image.\0")
|
|
return null
|
|
}
|
|
|
|
surface := new_surface(width, height)
|
|
index := @as([Color; 64], idk)
|
|
|
|
run := 0
|
|
px := Color.(0, 0, 0, 255)
|
|
px_pos := 0
|
|
|
|
total_pixels := width * height
|
|
|
|
loop if px_pos >= total_pixels break else {
|
|
if run > 0 {
|
|
run -= 1
|
|
} else {
|
|
b1 := *qoi
|
|
qoi += 1
|
|
|
|
if b1 == QOI_OP_RGB {
|
|
px.r = *qoi
|
|
px.g = *(qoi + 1)
|
|
px.b = *(qoi + 2)
|
|
qoi += 3
|
|
} else if b1 == QOI_OP_RGBA {
|
|
px.r = *qoi
|
|
px.g = *(qoi + 1)
|
|
px.b = *(qoi + 2)
|
|
px.a = *(qoi + 3)
|
|
qoi += 4
|
|
} else if (b1 & QOI_MASK_2) == QOI_OP_INDEX {
|
|
px = index[b1 & 0x3F]
|
|
} else if (b1 & QOI_MASK_2) == QOI_OP_DIFF {
|
|
px.r = px.r + (b1 >> 4 & 0x3) - 2 & 0xFF
|
|
px.g = px.g + (b1 >> 2 & 0x3) - 2 & 0xFF
|
|
px.b = px.b + (b1 & 0x3) - 2 & 0xFF
|
|
} else if (b1 & QOI_MASK_2) == QOI_OP_LUMA {
|
|
b2 := *qoi
|
|
vg := (b1 & 0x3F) - 32
|
|
|
|
px.r = px.r + vg - 8 + (b2 >> 4 & 0xF) & 0xFF
|
|
px.g = px.g + vg & 0xFF
|
|
px.b = px.b + vg - 8 + (b2 & 0xF) & 0xFF
|
|
qoi += 1
|
|
} else if (b1 & QOI_MASK_2) == QOI_OP_RUN {
|
|
run = b1 & 0x3F
|
|
}
|
|
|
|
index[@inline(QOI_COLOR_HASH, px)] = px
|
|
};
|
|
|
|
*(surface.buf + px_pos) = px
|
|
|
|
px_pos += 1
|
|
}
|
|
|
|
return surface
|
|
} |