2015-02-24 15:17:50 +00:00
|
|
|
/* ReC98
|
|
|
|
* -----
|
2015-03-03 05:47:23 +00:00
|
|
|
* Main include file
|
2015-02-24 15:17:50 +00:00
|
|
|
*/
|
|
|
|
|
2015-03-03 05:47:23 +00:00
|
|
|
#include <master.h>
|
2015-03-16 21:35:52 +00:00
|
|
|
#include <stddef.h>
|
2019-12-11 20:42:27 +00:00
|
|
|
#include "platform.h"
|
2019-11-08 20:03:03 +00:00
|
|
|
#include "pc98.h"
|
2015-03-16 21:35:52 +00:00
|
|
|
|
|
|
|
// master.lib extensions
|
|
|
|
// ---------------------
|
|
|
|
#define palette_entry_rgb_show(fn) \
|
|
|
|
palette_entry_rgb(fn); \
|
|
|
|
palette_show();
|
2019-11-26 21:47:07 +00:00
|
|
|
|
|
|
|
// RGB color triple, used for the Palettes structure
|
|
|
|
typedef union {
|
|
|
|
struct {
|
|
|
|
unsigned char r, g, b;
|
|
|
|
} c;
|
|
|
|
unsigned char v[3];
|
|
|
|
} rgb_t;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
rgb_t colors[16];
|
|
|
|
} palette_t;
|
2015-03-16 21:35:52 +00:00
|
|
|
// ---------------------
|
2015-03-03 05:47:23 +00:00
|
|
|
|
2015-03-01 21:52:25 +00:00
|
|
|
// Macros
|
|
|
|
// ------
|
|
|
|
#define CLAMP_INC(val, max) \
|
|
|
|
(val)++; \
|
|
|
|
if((val) > (max)) { \
|
|
|
|
(val) = (max); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CLAMP_DEC(val, min) \
|
|
|
|
(val)--; \
|
|
|
|
if((val) < (min)) { \
|
|
|
|
(val) = (min); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RING_INC(val, ring_end) \
|
|
|
|
(val)++; \
|
|
|
|
if((val) > (ring_end)) { \
|
|
|
|
(val) = 0; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define RING_DEC(val, ring_end) \
|
|
|
|
(val)--; \
|
|
|
|
if((val) < 0) { \
|
|
|
|
(val) = ring_end; \
|
|
|
|
}
|
2015-03-07 16:35:30 +00:00
|
|
|
|
|
|
|
// Resident structure
|
|
|
|
#define RES_ID_LEN sizeof(RES_ID)
|
|
|
|
#define RES_ID_STRLEN (RES_ID_LEN - 1)
|
|
|
|
#define RES_PARASIZE ((sizeof(resident_t) + 0xF) >> 4)
|
2015-03-01 21:52:25 +00:00
|
|
|
// ------
|
|
|
|
|
2019-11-30 14:48:36 +00:00
|
|
|
typedef union {
|
|
|
|
struct {
|
2019-12-11 20:42:27 +00:00
|
|
|
int8_t lo, hi;
|
2019-11-30 14:48:36 +00:00
|
|
|
} byte;
|
2019-12-11 20:42:27 +00:00
|
|
|
int16_t v;
|
2019-11-30 14:48:36 +00:00
|
|
|
} twobyte_t;
|
|
|
|
|
2019-09-15 14:09:08 +00:00
|
|
|
/// Typedefs
|
|
|
|
/// --------
|
|
|
|
// Generic callback function types. Note the difference between function
|
|
|
|
// distance (nearfunc / farfunc) and pointer variable distance
|
|
|
|
// (t_near / t_far).
|
|
|
|
typedef void (near pascal *near nearfunc_t_near)(void);
|
|
|
|
typedef void ( far pascal *near farfunc_t_near)(void);
|
|
|
|
typedef void (near pascal * far nearfunc_t_far)(void);
|
|
|
|
typedef void ( far pascal * far farfunc_t_far)(void);
|
|
|
|
/// --------
|
|
|
|
|
2015-03-01 21:52:25 +00:00
|
|
|
// PC-98 VRAM planes
|
|
|
|
// -----------------
|
2019-12-12 14:01:13 +00:00
|
|
|
// Planar 1bpp types, describing horizontal lines of 8, 16, or 32 pixels.
|
|
|
|
typedef uint8_t planar8_t;
|
|
|
|
typedef uint16_t planar16_t;
|
|
|
|
typedef uint32_t planar32_t;
|
|
|
|
// ... and the same for the rare cases where ZUN's code used signed types.
|
|
|
|
typedef int8_t splanar8_t;
|
|
|
|
typedef int16_t splanar16_t;
|
|
|
|
typedef int32_t splanar32_t;
|
|
|
|
|
2015-02-24 15:17:50 +00:00
|
|
|
typedef enum {
|
|
|
|
PL_B, PL_R, PL_G, PL_E, PL_COUNT
|
|
|
|
} vram_plane_t;
|
|
|
|
|
[C decompilation] [th01/reiiden] Randomly shaped VRAM copy functions, #1
So apparently, TH01 isn't double-buffered in the usual sense, and instead uses
the second hardware framebuffer (page 1) exclusively to keep the background
image and any non-animated sprites, including the cards. Then, in order to
limit flickering when animating the bullet, character and boss sprites on top
of that (or just to the limit number of VRAM accesses, who knows), ZUN goes to
great lengths and tries to make sure to only copy back the pixels that were
modified on plane 0 in the last frame.
(Which doesn't work that well though. When you play the game, you still notice
tons of flickering whenever sprites overlap.)
And by "great lengths", I mean "having a separate counterpart function for
each shape and sprite animated which recalculates and copies back the same
pixels from plane 1 to plane 0", because that's what the new functions here
lead me to believe. Both of them are only called at one place: the wave
function on the second half of Elis' entrance animation, and the horizontal
masked line function for Reimu's X attack animations.
2015-03-10 16:39:00 +00:00
|
|
|
typedef struct {
|
2019-12-12 14:01:13 +00:00
|
|
|
planar8_t B, R, G, E;
|
[C decompilation] [th01/reiiden] Randomly shaped VRAM copy functions, #1
So apparently, TH01 isn't double-buffered in the usual sense, and instead uses
the second hardware framebuffer (page 1) exclusively to keep the background
image and any non-animated sprites, including the cards. Then, in order to
limit flickering when animating the bullet, character and boss sprites on top
of that (or just to the limit number of VRAM accesses, who knows), ZUN goes to
great lengths and tries to make sure to only copy back the pixels that were
modified on plane 0 in the last frame.
(Which doesn't work that well though. When you play the game, you still notice
tons of flickering whenever sprites overlap.)
And by "great lengths", I mean "having a separate counterpart function for
each shape and sprite animated which recalculates and copies back the same
pixels from plane 1 to plane 0", because that's what the new functions here
lead me to believe. Both of them are only called at one place: the wave
function on the second half of Elis' entrance animation, and the horizontal
masked line function for Reimu's X attack animations.
2015-03-10 16:39:00 +00:00
|
|
|
} vram_planar_8_pixels_t;
|
|
|
|
|
|
|
|
typedef struct {
|
2019-12-12 14:01:13 +00:00
|
|
|
planar16_t B, R, G, E;
|
[C decompilation] [th01/reiiden] Randomly shaped VRAM copy functions, #1
So apparently, TH01 isn't double-buffered in the usual sense, and instead uses
the second hardware framebuffer (page 1) exclusively to keep the background
image and any non-animated sprites, including the cards. Then, in order to
limit flickering when animating the bullet, character and boss sprites on top
of that (or just to the limit number of VRAM accesses, who knows), ZUN goes to
great lengths and tries to make sure to only copy back the pixels that were
modified on plane 0 in the last frame.
(Which doesn't work that well though. When you play the game, you still notice
tons of flickering whenever sprites overlap.)
And by "great lengths", I mean "having a separate counterpart function for
each shape and sprite animated which recalculates and copies back the same
pixels from plane 1 to plane 0", because that's what the new functions here
lead me to believe. Both of them are only called at one place: the wave
function on the second half of Elis' entrance animation, and the horizontal
masked line function for Reimu's X attack animations.
2015-03-10 16:39:00 +00:00
|
|
|
} vram_planar_16_pixels_t;
|
|
|
|
|
2015-02-24 15:17:50 +00:00
|
|
|
// Since array subscripts create slightly different assembly in places, we
|
|
|
|
// offer both variants.
|
2019-12-12 14:01:13 +00:00
|
|
|
extern planar8_t *VRAM_PLANE[PL_COUNT];
|
|
|
|
extern planar8_t *VRAM_PLANE_B;
|
|
|
|
extern planar8_t *VRAM_PLANE_G;
|
|
|
|
extern planar8_t *VRAM_PLANE_R;
|
|
|
|
extern planar8_t *VRAM_PLANE_E;
|
2015-02-24 14:45:38 +00:00
|
|
|
|
|
|
|
#define PLANE_DWORD_BLIT(dst, src) \
|
2019-12-12 14:01:13 +00:00
|
|
|
for(p = 0; p < PLANE_SIZE; p += (int)sizeof(planar32_t)) { \
|
|
|
|
*(planar32_t*)((dst) + p) = *(planar32_t*)((src) + p); \
|
2015-02-24 14:45:38 +00:00
|
|
|
}
|
2015-02-25 22:05:20 +00:00
|
|
|
|
|
|
|
#define VRAM_OFFSET(x, y) ((x) >> 3) + (y << 6) + (y << 4)
|
2015-03-14 22:25:50 +00:00
|
|
|
|
|
|
|
void pascal vram_planes_set(void);
|
2015-03-01 21:52:25 +00:00
|
|
|
// -----------------
|