2020-03-14 13:36:17 +00:00
|
|
|
|
/// Uncompressed 16-color 32×32 sprite format
|
|
|
|
|
/// -----------------------------------------
|
2020-03-16 17:54:02 +00:00
|
|
|
|
/// Provides functions for both 32×32 and 16×16 sprites, and optionally
|
|
|
|
|
/// supports transparency for images loaded from .PTN files, hardcoded to
|
2020-06-18 18:01:29 +00:00
|
|
|
|
/// color #15. With functions for raw allocation and VRAM snapping, this can
|
|
|
|
|
/// also be used to store the backgrounds of frequently updated VRAM regions.
|
2020-03-14 13:36:17 +00:00
|
|
|
|
|
2022-08-14 01:39:08 +00:00
|
|
|
|
#define PTN_HPP
|
|
|
|
|
|
2020-06-06 21:28:03 +00:00
|
|
|
|
// Color #15 (1111) is always the transparent one, meaning that transparent
|
|
|
|
|
// dots are 1 in all 4 bitplanes. The alpha mask therefore simply is the
|
|
|
|
|
// negation of ANDing all bitplanes together. Nifty!
|
2022-07-07 12:36:07 +00:00
|
|
|
|
template <class T> inline T ptn_alpha_from(T B, T R, T G, T E) {
|
2020-06-06 21:28:03 +00:00
|
|
|
|
return ~((B) & (R) & (G) & (E));
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-14 13:36:17 +00:00
|
|
|
|
#define PTN_W 32
|
|
|
|
|
#define PTN_H 32
|
|
|
|
|
|
2022-05-31 18:53:33 +00:00
|
|
|
|
#include "th01/sprites/main_ptn.h"
|
|
|
|
|
|
2021-04-17 18:08:30 +00:00
|
|
|
|
typedef dot_rect_t(PTN_W, PTN_H) ptn_plane_t;
|
2020-03-14 13:36:17 +00:00
|
|
|
|
|
|
|
|
|
// On-disk per-image structure
|
|
|
|
|
struct ptn_file_image_t {
|
|
|
|
|
int8_t unused_zero;
|
2020-07-19 09:52:26 +00:00
|
|
|
|
Planar<ptn_plane_t> planes;
|
2020-03-14 13:36:17 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// In-memory per-image structure
|
|
|
|
|
struct ptn_t : public ptn_file_image_t {
|
2021-04-17 18:08:30 +00:00
|
|
|
|
ptn_plane_t alpha; // Derived from color #15 at load time
|
2020-03-14 13:36:17 +00:00
|
|
|
|
};
|
|
|
|
|
|
2022-08-12 23:17:03 +00:00
|
|
|
|
template <class T> inline int32_t ptn_sizeof_array(const T& count) {
|
|
|
|
|
return (count * static_cast<int32_t>(sizeof(ptn_t)));
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-14 13:36:17 +00:00
|
|
|
|
extern ptn_t* ptn_images[PTN_SLOT_COUNT];
|
2022-08-12 23:17:03 +00:00
|
|
|
|
extern int8_t ptn_image_count[PTN_SLOT_COUNT];
|
2020-03-16 17:54:02 +00:00
|
|
|
|
|
2021-11-01 15:17:50 +00:00
|
|
|
|
// MODDERS: Make [id] unsigned
|
|
|
|
|
static inline ptn_t* ptn_with_id(int id) {
|
|
|
|
|
return &ptn_images[id / PTN_IMAGES_PER_SLOT][id % PTN_IMAGES_PER_SLOT];
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-16 17:54:02 +00:00
|
|
|
|
// Loading and freeing
|
|
|
|
|
// -------------------
|
|
|
|
|
typedef enum {
|
|
|
|
|
PE_OK = 0,
|
|
|
|
|
PE_OUT_OF_MEMORY = -3,
|
|
|
|
|
PE_IMAGE_COUNT_INVALID = -9,
|
2020-03-29 15:08:04 +00:00
|
|
|
|
|
2020-09-12 08:17:55 +00:00
|
|
|
|
_ptn_error_t_FORCE_UINT16 = 0xFFFF
|
2020-03-16 17:54:02 +00:00
|
|
|
|
} ptn_error_t;
|
|
|
|
|
|
|
|
|
|
// Frees all images in [slot], then allocates new memory for the given number
|
|
|
|
|
// of images.
|
2021-11-01 15:17:50 +00:00
|
|
|
|
ptn_error_t ptn_new(main_ptn_slot_t slot, int image_count);
|
2020-03-16 17:54:02 +00:00
|
|
|
|
|
|
|
|
|
// Frees all images in [slot], then loads all images from the .PTN file with
|
|
|
|
|
// the given name into the same slot, retaining the current hardware palette.
|
|
|
|
|
// Also derives the alpha plane from color #15 of every image.
|
2021-11-01 15:17:50 +00:00
|
|
|
|
void ptn_load(main_ptn_slot_t slot, const char *fn);
|
2020-03-16 17:54:02 +00:00
|
|
|
|
|
|
|
|
|
// Like ptn_load(), but sets the hardware palette to the one in [fn]'s header.
|
2021-11-01 15:17:50 +00:00
|
|
|
|
ptn_error_t ptn_load_palette_show(main_ptn_slot_t slot, const char *fn);
|
2020-03-16 17:54:02 +00:00
|
|
|
|
|
|
|
|
|
// Frees all images in [slot].
|
2021-11-01 15:17:50 +00:00
|
|
|
|
void ptn_free(main_ptn_slot_t slot);
|
2020-03-16 17:54:02 +00:00
|
|
|
|
// -------------------
|
|
|
|
|
|
2020-06-06 18:53:23 +00:00
|
|
|
|
// If true, the affected 32×32 or 16×16 area is restored from VRAM page 1
|
|
|
|
|
// before a byte-aligned alpha put operation.
|
2020-07-04 18:20:51 +00:00
|
|
|
|
// (Because calling egc_copy_rect_1_to_0_16() yourself is way too much to ask?)
|
2022-06-06 19:28:36 +00:00
|
|
|
|
//
|
|
|
|
|
// ZUN bug: egc_copy_rect_1_to_0_16() is word-aligned rather than byte-aligned.
|
|
|
|
|
// Blitting to a non-word-aligned X position will cause an additional 8 pixels
|
|
|
|
|
// to the left and/or right side of the sprite to be unblitted as well.
|
|
|
|
|
// Really, this hack should never be used.
|
|
|
|
|
extern bool ptn_sloppy_unput_before_alpha_put;
|
2020-06-06 18:53:23 +00:00
|
|
|
|
|
2020-03-16 17:54:02 +00:00
|
|
|
|
// 32×32 access
|
|
|
|
|
// ------------
|
2022-03-11 23:48:15 +00:00
|
|
|
|
#define vram_put_ptn_planar(vo, ptn, y) \
|
2020-11-20 21:00:23 +00:00
|
|
|
|
VRAM_PUT(B, vo, ptn->planes.B[y], PTN_W); \
|
|
|
|
|
VRAM_PUT(R, vo, ptn->planes.R[y], PTN_W); \
|
|
|
|
|
VRAM_PUT(G, vo, ptn->planes.G[y], PTN_W); \
|
|
|
|
|
VRAM_PUT(E, vo, ptn->planes.E[y], PTN_W);
|
|
|
|
|
|
2022-03-11 23:48:15 +00:00
|
|
|
|
#define vram_snap_ptn_planar(ptn, y, vo) \
|
2020-11-21 15:53:53 +00:00
|
|
|
|
VRAM_SNAP(ptn->planes.B[y], B, vo, PTN_W); \
|
|
|
|
|
VRAM_SNAP(ptn->planes.R[y], R, vo, PTN_W); \
|
|
|
|
|
VRAM_SNAP(ptn->planes.G[y], G, vo, PTN_W); \
|
|
|
|
|
VRAM_SNAP(ptn->planes.E[y], E, vo, PTN_W);
|
|
|
|
|
|
2020-06-18 18:01:29 +00:00
|
|
|
|
// Displays the given [ptn_id] at (⌊left/8⌋*8, top), disregarding its alpha
|
2020-03-16 17:54:02 +00:00
|
|
|
|
// plane.
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_put_noalpha_8(screen_x_t left, vram_y_t top, int ptn_id);
|
2020-03-17 20:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Overwrites the 4 color planes of [ptn_id] with the current VRAM content of
|
|
|
|
|
// the 32×32 pixels starting at (⌊left/8⌋*8, top).
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_snap_8(screen_x_t left, vram_y_t top, int ptn_id);
|
2020-03-19 13:12:13 +00:00
|
|
|
|
|
|
|
|
|
// Copies the 32×32 pixels starting at (⌊left/8⌋*8, top) from VRAM page 0 to
|
|
|
|
|
// VRAM page 1.
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_copy_8_0_to_1(screen_x_t left, vram_y_t top);
|
2020-06-06 14:48:29 +00:00
|
|
|
|
|
2021-09-16 17:13:14 +00:00
|
|
|
|
// Restores the 32×32 pixels starting at (⌊left/16⌋*16, top) on VRAM page 0
|
|
|
|
|
// with the same (background) pixels from VRAM page 1.
|
|
|
|
|
#define ptn_sloppy_unput_16(left, top) \
|
|
|
|
|
egc_copy_rect_1_to_0_16(left, top, PTN_W, PTN_H)
|
|
|
|
|
|
2020-06-06 14:48:29 +00:00
|
|
|
|
// Restores the 32×32 pixels starting at (⌊left/8⌋*8, top) on VRAM page 0 with
|
|
|
|
|
// the same (background) pixels from VRAM page 1, applying the alpha mask from
|
|
|
|
|
// the given [ptn_id].
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_unput_8(screen_x_t left, vram_y_t top, int ptn_id);
|
2020-06-06 18:53:23 +00:00
|
|
|
|
|
|
|
|
|
// Displays the given [ptn_id] at (⌊left/8⌋*8, top).
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_put_8(screen_x_t left, vram_y_t top, int ptn_id);
|
2020-03-16 17:54:02 +00:00
|
|
|
|
// ------------
|
|
|
|
|
|
|
|
|
|
// 16×16 access
|
|
|
|
|
// ------------
|
|
|
|
|
// These functions subdivide a 32×32 PTN image into four 16×16 areas, numbered
|
|
|
|
|
// like this:
|
|
|
|
|
// | 0 | 1 |
|
|
|
|
|
// | 2 | 3 |
|
2022-08-04 13:29:34 +00:00
|
|
|
|
|
2020-03-16 17:54:02 +00:00
|
|
|
|
#define PTN_QUARTER_W 16
|
|
|
|
|
#define PTN_QUARTER_H 16
|
|
|
|
|
|
|
|
|
|
#define ptn_quarter_y(quarter) ((quarter & 2) ? PTN_QUARTER_H : 0)
|
|
|
|
|
#define ptn_quarter_x(quarter) ((quarter & 1) ? PTN_QUARTER_W : 0)
|
|
|
|
|
|
|
|
|
|
struct PTNQuarter
|
|
|
|
|
{
|
2020-08-21 18:13:08 +00:00
|
|
|
|
pixel_t x, y;
|
2020-03-16 17:54:02 +00:00
|
|
|
|
|
|
|
|
|
void init(const int& quarter) {
|
|
|
|
|
y = ptn_quarter_y(quarter);
|
|
|
|
|
x = ptn_quarter_x(quarter);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Displays the given [quarter] of the given [ptn_id] at (⌊left/8⌋*8, top),
|
|
|
|
|
// diregarding its alpha plane.
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_put_quarter_noalpha_8(
|
|
|
|
|
screen_x_t left, vram_y_t top, int ptn_id, int quarter
|
|
|
|
|
);
|
2020-03-17 20:04:24 +00:00
|
|
|
|
|
|
|
|
|
// Overwrites the 4 color planes of the given [quarter] of [ptn_id] with the
|
|
|
|
|
// current VRAM content of the 16×16 pixels starting at (⌊left/8⌋*8, top).
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_snap_quarter_8(
|
|
|
|
|
screen_x_t left, vram_y_t top, int ptn_id, int quarter
|
|
|
|
|
);
|
2020-06-06 19:28:30 +00:00
|
|
|
|
|
2021-09-16 17:13:14 +00:00
|
|
|
|
// Restores the 16×16 pixels starting at (⌊left/16⌋*16, top) on VRAM page 0
|
|
|
|
|
// with the same (background) pixels from VRAM page 1.
|
|
|
|
|
#define ptn_sloppy_unput_quarter_16(left, top) \
|
|
|
|
|
egc_copy_rect_1_to_0_16(left, top, PTN_QUARTER_W, PTN_QUARTER_H)
|
|
|
|
|
|
2020-06-06 19:28:30 +00:00
|
|
|
|
// Restores the 16×16 pixels starting at (⌊left/8⌋*8, top) on VRAM page 0 with
|
|
|
|
|
// the same (background) pixels from VRAM page 1, applying the alpha mask from
|
|
|
|
|
// the given [quarter] of [ptn_id].
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_unput_quarter_8(
|
|
|
|
|
screen_x_t left, vram_y_t top, int ptn_id, int quarter
|
|
|
|
|
);
|
2020-06-06 20:43:37 +00:00
|
|
|
|
|
|
|
|
|
// Displays the given [quarter] of the given [ptn_id] at (⌊left/8⌋*8, top).
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_put_quarter_8(
|
|
|
|
|
screen_x_t left, vram_y_t top, int ptn_id, int quarter
|
|
|
|
|
);
|
2020-06-07 09:19:29 +00:00
|
|
|
|
|
|
|
|
|
// Displays the given [quarter] of the given [ptn_id] at (left, top).
|
2020-08-20 19:59:45 +00:00
|
|
|
|
void ptn_put_quarter(screen_x_t left, vram_y_t top, int ptn_id, int quarter);
|
2020-03-16 17:54:02 +00:00
|
|
|
|
// ------------
|
2021-10-30 13:20:24 +00:00
|
|
|
|
|
|
|
|
|
// Rectangular access
|
|
|
|
|
// ------------------
|
|
|
|
|
|
|
|
|
|
// Calls [func] for every .PTN along a (⌈w/32⌉*32 × 32) row of successive
|
|
|
|
|
// sprites starting at (⌊left/8⌋*8, top), and [image_first] in [slot].
|
|
|
|
|
#define ptn_row(func, left, top, w, slot, image_first, tmp_ptn_x) { \
|
|
|
|
|
for(tmp_ptn_x = 0; tmp_ptn_x < (w / PTN_W); tmp_ptn_x++) { \
|
|
|
|
|
func((left + (tmp_ptn_x * PTN_W)), top, PTN_ID(slot, image_first)); \
|
|
|
|
|
image_first++; \
|
|
|
|
|
} \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Overwrites the 4 color planes of the successive .PTN sprites starting at
|
|
|
|
|
// [image_first] in [slot] with the current content of the
|
|
|
|
|
// (⌈w/32⌉*32 × ⌈h/32⌉*32) rectangle starting at (⌊left/8⌋*8, top) on VRAM page
|
|
|
|
|
// 1.
|
|
|
|
|
#define ptn_snap_rect_from_1_8( \
|
|
|
|
|
left, top, w, h, slot, image_first, tmp_ptn_x, tmp_ptn_y \
|
|
|
|
|
) { \
|
|
|
|
|
graph_accesspage_func(1); \
|
|
|
|
|
for(tmp_ptn_y = 0; tmp_ptn_y < (h / PTN_H); tmp_ptn_y++) { \
|
|
|
|
|
ptn_row(ptn_snap_8, \
|
|
|
|
|
left, (top + (tmp_ptn_y * PTN_H)), w, slot, image_first, tmp_ptn_x \
|
|
|
|
|
); \
|
|
|
|
|
} \
|
|
|
|
|
graph_accesspage_func(0); \
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Blits a single (⌈w/32⌉*32 × 32) row of successive .PTN sprites, starting at
|
|
|
|
|
// [image_first] in [slot], to (⌊left/8⌋*8, top).
|
|
|
|
|
#define ptn_put_row_noalpha_8(left, top, w, slot, image_first, tmp_ptn_x) \
|
|
|
|
|
ptn_row(ptn_put_noalpha_8, left, top, w, slot, image_first, tmp_ptn_x)
|
|
|
|
|
|
|
|
|
|
// Blits a (⌈w/32⌉*32 × ⌈h/32⌉*32) rectangle of successive .PTN sprites,
|
|
|
|
|
// starting at [image_first] in [slot], to (⌊left/8⌋*8, top).
|
|
|
|
|
#define ptn_put_rect_noalpha_8( \
|
|
|
|
|
left, top, w, h, slot, image_first, tmp_ptn_x, tmp_ptn_y \
|
|
|
|
|
) { \
|
|
|
|
|
for(tmp_ptn_y = 0; tmp_ptn_y < (h / PTN_H); tmp_ptn_y++) { \
|
|
|
|
|
ptn_put_row_noalpha_8( \
|
|
|
|
|
left, (top + (tmp_ptn_y * PTN_H)), w, slot, image_first, tmp_ptn_x \
|
|
|
|
|
); \
|
|
|
|
|
} \
|
|
|
|
|
}
|
|
|
|
|
// ------------------
|
2020-03-14 13:36:17 +00:00
|
|
|
|
/// -----------------------------------------
|