- u32 flags, GLuint *dest )
-{
- u32 header_magic;
- qoi_rgba_t index[64];
- qoi_rgba_t px;
- int px_len, chunks_len, px_pos;
- int p = 0, run = 0;
-
- u32 channels = 4; /* TODO */
-
- qoi_desc desc;
-
- if (
- bytes == NULL ||
- (channels != 0 && channels != 3 && channels != 4) ||
- size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding)
- ) {
- vg_error( "Error while decoding qoi file: illegal parameters\n" );
- vg_tex2d_replace_with_error( dest );
- return;
- }
-
- header_magic = qoi_read_32(bytes, &p);
- desc.width = qoi_read_32(bytes, &p);
- desc.height = qoi_read_32(bytes, &p);
- desc.channels = bytes[p++];
- desc.colorspace = bytes[p++];
-
- if (
- desc.width == 0 || desc.height == 0 ||
- desc.channels < 3 || desc.channels > 4 ||
- desc.colorspace > 1 ||
- header_magic != QOI_MAGIC ||
- desc.height >= QOI_PIXELS_MAX / desc.width
- ) {
- vg_error( "Error while decoding qoi file: invalid file\n" );
- vg_tex2d_replace_with_error( dest );
- return;
- }
-
- if (channels == 0) {
- channels = desc.channels;
- }
-
- px_len = desc.width * desc.height * channels;
-
- /* allocate async call
- * --------------------------
- */
- u32 hdr_size = vg_align8(sizeof(struct texture_load_info)),
- tex_size = vg_align8(px_len);
-
- vg_async_item *call = vg_async_alloc( hdr_size + tex_size );
- struct texture_load_info *info = call->payload;
-
- info->dest = dest;
- info->flags = flags;
- info->width = desc.width;
- info->height = desc.height;
- info->rgba = ((u8*)call->payload) + hdr_size;
-
- /*
- * Decode
- * ----------------------------
- */
-
- u8 *pixels = info->rgba;
-
- QOI_ZEROARR(index);
- px.rgba.r = 0;
- px.rgba.g = 0;
- px.rgba.b = 0;
- px.rgba.a = 255;
-
- chunks_len = size - (int)sizeof(qoi_padding);
- for (px_pos = 0; px_pos < px_len; px_pos += channels) {
- if (run > 0) {
- run--;
- }
- else if (p < chunks_len) {
- int b1 = bytes[p++];
-
- if (b1 == QOI_OP_RGB) {
- px.rgba.r = bytes[p++];
- px.rgba.g = bytes[p++];
- px.rgba.b = bytes[p++];
- }
- else if (b1 == QOI_OP_RGBA) {
- px.rgba.r = bytes[p++];
- px.rgba.g = bytes[p++];
- px.rgba.b = bytes[p++];
- px.rgba.a = bytes[p++];
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) {
- px = index[b1];
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) {
- px.rgba.r += ((b1 >> 4) & 0x03) - 2;
- px.rgba.g += ((b1 >> 2) & 0x03) - 2;
- px.rgba.b += ( b1 & 0x03) - 2;
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) {
- int b2 = bytes[p++];
- int vg = (b1 & 0x3f) - 32;
- px.rgba.r += vg - 8 + ((b2 >> 4) & 0x0f);
- px.rgba.g += vg;
- px.rgba.b += vg - 8 + (b2 & 0x0f);
- }
- else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) {
- run = (b1 & 0x3f);
- }
-
- index[QOI_COLOR_HASH(px) % 64] = px;
- }
-
- pixels[px_pos + 0] = px.rgba.r;
- pixels[px_pos + 1] = px.rgba.g;
- pixels[px_pos + 2] = px.rgba.b;
-
- if (channels == 4) {
- pixels[px_pos + 3] = px.rgba.a;
- }
- }
-
- /*
- * Complete the call
- * --------------------------
- */
-
- vg_async_dispatch( call, async_vg_tex2d_upload );
-}
-
-VG_STATIC
-void vg_tex2d_load_qoi_async_file( const char *path, u32 flags, GLuint *dest )
-{
- vg_linear_clear( vg_mem.scratch );
-
- u32 size;
- const void *data = vg_file_read( vg_mem.scratch, path, &size );
- vg_tex2d_load_qoi_async( data, size, flags, dest );
-}