Files
allegro_qoi/allegro_qoi.c
2026-01-28 14:28:28 -06:00

108 lines
2.9 KiB
C

#include <stdlib.h>
#define QOI_IMPLEMENTATION
#include <qoi.h>
#include <allegro5/allegro5.h>
#include <allegro5/bitmap.h>
#include <allegro5/bitmap_io.h>
#include <allegro5/bitmap_lock.h>
#include <allegro5/color.h>
#include <allegro5/file.h>
#include <allegro5/allegro_font.h>
ALLEGRO_FONT* _al_load_bitmap_font(const char *filename, int size, int flags);
#ifdef __cplusplus
extern "C" {
#endif
ALLEGRO_BITMAP* _al_load_qoi_f(ALLEGRO_FILE* file, int flags) {
qoi_desc meta;
ALLEGRO_PIXEL_FORMAT fmt;
uint8_t* file_bytes = malloc(al_fsize(file));
memset(file_bytes, 0, al_fsize(file));
void* file_pos = file_bytes;
#define chunk_size 1024
al_fseek(file, 0, SEEK_SET);
while (!al_feof(file))
file_pos += al_fread(file, file_pos, chunk_size);
void* data = qoi_decode(file_bytes, al_fsize(file), &meta, 0);
free(file_bytes); if (!data) return NULL;
int oldflags = al_get_new_bitmap_flags();
al_set_new_bitmap_flags(flags);
switch (meta.channels) {
case 3: fmt = ALLEGRO_PIXEL_FORMAT_BGR_888; break;
case 4: fmt = ALLEGRO_PIXEL_FORMAT_ABGR_8888; break;
default: free(data); return NULL; break;
}
ALLEGRO_BITMAP* bmp = al_create_bitmap(meta.width, meta.height);
ALLEGRO_LOCKED_REGION* lock = al_lock_bitmap(
bmp, fmt,
ALLEGRO_LOCK_WRITEONLY
);
al_set_new_bitmap_flags(oldflags);
if (!lock) return NULL;
const int qoi_pitch = meta.width * meta.channels;
for (int i = 0; i < meta.height; i++) {
memcpy(lock->data + lock->pitch*i, data + qoi_pitch*i, qoi_pitch);
if (fmt == ALLEGRO_PIXEL_FORMAT_ABGR_8888
&& !(flags & ALLEGRO_NO_PREMULTIPLIED_ALPHA))
for (int p = 0; p < meta.width; p++) {
uint8_t* pixbytes = (lock->data + lock->pitch*i + p*4);
pixbytes[0] *= pixbytes[3]/255.0;
pixbytes[1] *= pixbytes[3]/255.0;
pixbytes[2] *= pixbytes[3]/255.0;
}
}
al_unlock_bitmap(bmp);
free(data); return bmp;
}
ALLEGRO_BITMAP* _al_load_qoi(const char* filename, int flags) {
ALLEGRO_FILE* fp;
ALLEGRO_BITMAP* bmp;
ALLEGRO_ASSERT(filename);
fp = al_fopen(filename, "rb");
if (!fp) {
//ALLEGRO_ERROR("Unable to open %s for reading.\n", filename);
return NULL;
}
bmp = _al_load_qoi_f(fp, flags);
al_fclose(fp);
return bmp;
}
bool _al_identify_qoi(ALLEGRO_FILE* f) {
uint32_t magic_expected = 1718185841;
uint32_t magic_found = al_fread32le(f);
if (magic_found != magic_expected)
return false;
if (!al_fseek(f, 14 - 4, ALLEGRO_SEEK_CUR)) // check for min size 14-byte header minus 32-bit magic
return false;
return true;
}
bool al_init_qoi() {
int insane = 0;
insane |= al_register_bitmap_loader(".qoi", _al_load_qoi);
insane |= al_register_bitmap_loader_f(".qoi", _al_load_qoi_f);
insane |= al_register_bitmap_identifier(".qoi", _al_identify_qoi);
return insane;
}
bool al_init_qoi_font() {
int insane = 0;
insane |= al_register_font_loader(".qoi", _al_load_bitmap_font);
return insane;
}
#ifdef __cplusplus
}
#endif