ReC98/th01/main/shape.cpp

236 lines
5.9 KiB
C++

#include "th01/v_colors.hpp"
#include "th01/sprites/shape8x8.hpp"
#include "th01/main/shape.hpp"
#define shape8x8_put(shape, left, top, col) \
dot_rect_t(8, 8) sprite = sSHAPE8X8[shape]; \
vram_offset_t vram_offset_topleft = vram_offset_divmul(left, top); \
int first_bit = (left % BYTE_DOTS); \
if((left < 0) || (left >= RES_X) || (top < 0) || (top >= RES_Y)) { \
return; \
} \
grcg_put_8x8_mono(vram_offset_topleft, first_bit, sprite.row, col);
void shape8x8_diamond_put(screen_x_t left, vram_y_t top, int col)
{
shape8x8_put(SHAPE8X8_DIAMOND, left, top, col);
}
void shape8x8_star_put(screen_x_t left, vram_y_t top, int col)
{
shape8x8_put(SHAPE8X8_STAR, left, top, col);
}
void shape8x8_flake_put(screen_x_t left, vram_y_t top, int col)
{
shape8x8_put(SHAPE8X8_FLAKE, left, top, col);
}
void shape_ellipse_arc_put(
screen_x_t center_x,
vram_y_t center_y,
pixel_t radius_x,
pixel_t radius_y,
int col,
unsigned char angle_step,
unsigned char angle_start,
unsigned char angle_end
)
{
int angle; // 16 bits to correctly work for an [angle_end] of 0xFF
dots8_t cache_dots = 0;
vram_offset_t cache_vram_offset = -1;
// ZUN bug: Leaves the GRCG activated if the return condition below is
// `true`. Should be done after that branch instead.
grcg_setcolor_rmw(col);
// Note that due to the cache, this function doesn't end up drawing
// anything if [angle_start] == [angle_end] either. (This actually happens
// in Elis' pattern_pellets_along_circle().)
if(angle_start > angle_end) {
return;
}
for(angle = angle_start; angle <= angle_end; angle += angle_step) {
vram_offset_t vram_offset;
screen_x_t cur_x = polar_x(center_x, radius_x, angle);
vram_y_t cur_y = polar_y(center_y, radius_y, angle);
vram_offset = vram_offset_shift(cur_x, cur_y);
if(cache_vram_offset != vram_offset) {
if(
(cur_x >= 0) && (cur_x < RES_X) &&
(cache_vram_offset >= 0) && (cache_vram_offset < PLANE_SIZE)
) {
grcg_put(cache_vram_offset, cache_dots, 8);
}
cache_dots = ((0x80) >> (cur_x & (BYTE_DOTS - 1)));
cache_vram_offset = vram_offset;
} else {
cache_dots |= ((0x80) >> (cur_x & (BYTE_DOTS - 1)));
}
}
grcg_off();
}
void shape_ellipse_arc_sloppy_unput(
screen_x_t center_x,
vram_y_t center_y,
pixel_t radius_x,
pixel_t radius_y,
unsigned char angle_step,
unsigned char angle_start,
unsigned char angle_end
)
{
int angle; // 16 bits to correctly work for an [angle_end] of 0xFF
// ZUN bug: Should all be initialized
screen_x_t cur_x;
vram_y_t cur_y;
screen_x_t prev_x;
vram_y_t prev_y;
if(angle_start > angle_end) {
return;
}
for(angle = angle_start; angle <= angle_end; angle += angle_step) {
cur_x = polar_x(center_x, radius_x, angle);
cur_y = polar_y(center_y, radius_y, angle);
if((prev_y != cur_y) || ((prev_x >> 3) != (cur_x >> 3))) {
egc_copy_rect_1_to_0_16(cur_x, cur_y, BYTE_DOTS, 1);
prev_x = cur_x;
prev_y = cur_y;
}
}
}
void shape8x8_invincibility_put_with_mask_from_B_plane(
screen_x_t left, vram_y_t top, int cel
);
void shape8x8_invincibility_put(screen_x_t left, vram_y_t top, int cel)
{
if(left < 0) {
return;
}
shape8x8_invincibility_put_with_mask_from_B_plane(left, top, cel);
vram_offset_t vram_offset = vram_offset_divmul(left, top);
int first_bit = (left % BYTE_DOTS);
if(cel > (SHAPE8X8_INVINCIBILITY_CELS - 1)) {
return;
}
grcg_setcolor_rmw(V_RED);
for(pixel_t y = 0; y < sSHAPE8X8[0].h(); y++) {
#define sprite sSHAPE8X8[SHAPE8X8_INVINCIBILITY + cel][y]
if(first_bit == 0) {
grcg_put(vram_offset, sprite, 8);
} else {
grcg_put(
vram_offset, (
(sprite << ((BYTE_DOTS * 2) - first_bit)) +
(sprite >> first_bit)
),
16
);
}
vram_offset += ROW_SIZE;
if(vram_offset > PLANE_SIZE) { // Clip at the bottom edge
break;
}
#undef sprite
}
grcg_off();
}
// Surely this function was meant to just regularly unblit the sprite via the
// EGC, or even the GRCG's TCR mode? The RMW mode has no effect on VRAM reads,
// and simply returns the exact bytes at the given offset on the given (that
// is, the B) plane. As a result, this unblitting attempt actually blits the
// sprite again, masked by whatever was in VRAM plane B at the given position
// before calling this function.
void shape8x8_invincibility_put_with_mask_from_B_plane(
screen_x_t left, vram_y_t top, int cel
)
{
if(left < 0) {
return;
}
vram_offset_t vram_offset = vram_offset_divmul(left, top);
int first_bit = (left % BYTE_DOTS);
if(cel > (SHAPE8X8_INVINCIBILITY_CELS - 1)) {
return;
}
grcg_setcolor_rmw(V_RED);
for(pixel_t y = 0; y < sSHAPE8X8[0].h(); y++) {
#define sprite sSHAPE8X8[SHAPE8X8_INVINCIBILITY + cel][y]
if(first_bit == 0) {
dots8_t bg_B;
graph_accesspage_func(1);
bg_B = (grcg_chunk_8(vram_offset) & sprite);
graph_accesspage_func(0);
grcg_put_8(vram_offset, bg_B);
} else {
// MODDERS: Add clipping at the right edge
dots8_t bg_B_left;
dots8_t bg_B_right;
graph_accesspage_func(1);
bg_B_left = (grcg_chunk_8(vram_offset + 0) & (sprite >> first_bit));
graph_accesspage_func(1);
bg_B_right = (
grcg_chunk_8(vram_offset + 1) &
(sprite << (BYTE_DOTS - first_bit))
);
graph_accesspage_func(0); grcg_put_8((vram_offset + 0), bg_B_left);
graph_accesspage_func(0); grcg_put_8((vram_offset + 1), bg_B_right);
}
vram_offset += ROW_SIZE;
if(vram_offset > PLANE_SIZE) { // Clip at the bottom edge
break;
}
#undef sprite
}
grcg_off();
}
// Why is this here?
void graph_r_lineloop_put(
const screen_x_t x[], const vram_y_t y[], int point_count, int col
)
{
int i = 0;
while((point_count - 1) > i) {
graph_r_line(x[i], y[i], x[i + 1], y[i + 1], col);
i++;
}
graph_r_line(x[i], y[i], x[0], y[0], col);
}
void graph_r_lineloop_unput(
const screen_x_t x[], const vram_y_t y[], int point_count
)
{
int i = 0;
while((point_count - 1) > i) {
graph_r_line_unput(x[i], y[i], x[i + 1], y[i + 1]);
i++;
}
graph_r_line_unput(x[i], y[i], x[0], y[0]);
}