2020-08-05 11:30:55 +00:00
|
|
|
|
/// Uncompressed, 5-plane, 16-color + alpha, arbitrary-size sprite format
|
|
|
|
|
/// ---------------------------------------------------------------------
|
|
|
|
|
#define BOS_MAGIC "BOSS"
|
|
|
|
|
|
|
|
|
|
// On-disk per-file header. Not the same as for .GRC!
|
|
|
|
|
struct bos_header_t {
|
|
|
|
|
char magic[sizeof(BOS_MAGIC) - 1];
|
|
|
|
|
|
|
|
|
|
// Yes, this means that the *format* itself isn't actually restricted to
|
|
|
|
|
// word-aligned / 16w×h sizes, …
|
|
|
|
|
uint8_t vram_w;
|
|
|
|
|
|
|
|
|
|
int8_t zero;
|
|
|
|
|
uint8_t h;
|
|
|
|
|
int8_t unknown;
|
|
|
|
|
spriteformat_header_inner_t inner;
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-29 12:01:34 +00:00
|
|
|
|
#define BOS_IMAGES_PER_SLOT 8
|
|
|
|
|
|
2020-08-05 11:30:55 +00:00
|
|
|
|
// In-memory slot structures
|
2020-05-29 12:01:34 +00:00
|
|
|
|
struct bos_image_t {
|
2020-08-05 11:30:55 +00:00
|
|
|
|
// … as these types would suggest. That's purely an implementation choice.
|
2020-07-19 09:52:26 +00:00
|
|
|
|
Planar<dots16_t *> planes;
|
2020-05-29 12:01:34 +00:00
|
|
|
|
dots16_t *alpha;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct bos_t {
|
|
|
|
|
bos_image_t image[BOS_IMAGES_PER_SLOT];
|
|
|
|
|
};
|
|
|
|
|
|
2020-10-08 10:55:30 +00:00
|
|
|
|
// Shared loading and freeing subfunctions
|
|
|
|
|
// ---------------------------------------
|
|
|
|
|
|
|
|
|
|
// Separate function to work around the `Condition is always true/false` and
|
|
|
|
|
// `Unreachable code` warnings
|
|
|
|
|
inline void bos_header_load_palette(Palette4 &pal, bool load) {
|
|
|
|
|
if(load) {
|
|
|
|
|
arc_file_get_far(pal);
|
|
|
|
|
} else {
|
|
|
|
|
arc_file_seek(sizeof(spriteformat_header_t<bos_header_t>));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define bos_header_load(that, plane_size, fn, needlessly_load_the_palette) \
|
2020-09-25 12:52:38 +00:00
|
|
|
|
union { \
|
|
|
|
|
bos_header_t outer; \
|
|
|
|
|
Palette4 pal; \
|
|
|
|
|
int8_t space[50]; \
|
|
|
|
|
} header; \
|
|
|
|
|
\
|
|
|
|
|
arc_file_load(fn); \
|
|
|
|
|
\
|
|
|
|
|
arc_file_get_far(header.outer); \
|
|
|
|
|
that->vram_w = header.outer.vram_w; \
|
|
|
|
|
that->h = header.outer.h; \
|
|
|
|
|
that->bos_image_count = header.outer.inner.image_count; \
|
2020-10-08 10:55:30 +00:00
|
|
|
|
plane_size = (that->vram_w * that->h); \
|
|
|
|
|
bos_header_load_palette(header.pal, needlessly_load_the_palette);
|
2020-09-25 12:52:38 +00:00
|
|
|
|
|
|
|
|
|
#define bos_image_new(image, plane_size) \
|
|
|
|
|
image.alpha = new dots16_t[plane_size / 2]; \
|
|
|
|
|
image.planes.B = new dots16_t[plane_size / 2]; \
|
|
|
|
|
image.planes.R = new dots16_t[plane_size / 2]; \
|
|
|
|
|
image.planes.G = new dots16_t[plane_size / 2]; \
|
|
|
|
|
image.planes.E = new dots16_t[plane_size / 2];
|
|
|
|
|
|
2020-09-23 19:48:48 +00:00
|
|
|
|
// Always setting the pointer to NULL, for a change...
|
|
|
|
|
#define bos_image_ptr_free(ptr) \
|
|
|
|
|
if(ptr) { \
|
|
|
|
|
delete[] ptr; \
|
|
|
|
|
} \
|
|
|
|
|
ptr = NULL;
|
|
|
|
|
|
|
|
|
|
#define bos_free(slot_ptr) \
|
|
|
|
|
for(int image = 0; image < BOS_IMAGES_PER_SLOT; image++) { \
|
|
|
|
|
bos_image_ptr_free(slot_ptr.image[image].alpha); \
|
|
|
|
|
bos_image_ptr_free(slot_ptr.image[image].planes.B); \
|
|
|
|
|
bos_image_ptr_free(slot_ptr.image[image].planes.R); \
|
|
|
|
|
bos_image_ptr_free(slot_ptr.image[image].planes.G); \
|
|
|
|
|
bos_image_ptr_free(slot_ptr.image[image].planes.E); \
|
|
|
|
|
}
|
2020-10-08 10:55:30 +00:00
|
|
|
|
// ---------------------------------------
|
2020-09-23 19:48:48 +00:00
|
|
|
|
|
2020-09-23 21:28:50 +00:00
|
|
|
|
/// All functions that operate on this format are implemented redundantly for
|
|
|
|
|
/// both CBossEntity and CBossAnim, with their own respective entity arrays.
|
2020-08-05 11:30:55 +00:00
|
|
|
|
/// ---------------------------------------------------------------------
|