#include #define QOI_IMPLEMENTATION #include #include #include #include #include #include #include #include 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