Some video cleanups for better readability

This commit is contained in:
David Guillen Fandos 2023-07-11 23:11:27 +02:00
parent f5490a1996
commit 2391496432
2 changed files with 116 additions and 84 deletions

View File

@ -171,6 +171,8 @@ typedef enum
REG_HALTCNT = 0x180
} hardware_register;
#define REG_BGxCNT(n) (REG_BG0CNT + (n))
#define FLASH_DEVICE_UNDEFINED 0x00
#define FLASH_DEVICE_MACRONIX_64KB 0x1C
#define FLASH_DEVICE_AMTEL_64KB 0x3D

198
video.c
View File

@ -24,6 +24,10 @@ u16* gba_screen_pixels = NULL;
#define get_screen_pixels() gba_screen_pixels
#define get_screen_pitch() GBA_SCREEN_PITCH
typedef struct {
u16 attr0, attr1, attr2, attr3;
} t_oam;
static void render_scanline_conditional_tile(u32 start, u32 end, u16 *scanline,
u32 enable_flags, u32 dispcnt, u32 bldcnt, const tile_layer_render_struct
*layer_renderers);
@ -863,7 +867,7 @@ static void render_scanline_text_base_normal(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_base_normal(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -1050,7 +1054,7 @@ static void render_scanline_text_transparent_normal(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_transparent_normal(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -1236,7 +1240,7 @@ static void render_scanline_text_base_color16(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_base_color16(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -1421,7 +1425,7 @@ static void render_scanline_text_transparent_color16(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_transparent_color16(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -1606,7 +1610,7 @@ static void render_scanline_text_base_color32(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_base_color32(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -1791,7 +1795,7 @@ static void render_scanline_text_transparent_color32(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_transparent_color32(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -1978,7 +1982,7 @@ static void render_scanline_text_base_alpha(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_base_alpha(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -2161,7 +2165,7 @@ static void render_scanline_text_transparent_alpha(u32 layer,
u32 start, u32 end, void *scanline)
{
render_scanline_extra_variables_transparent_alpha(text);
u32 bg_control = read_ioreg(REG_BG0CNT + layer);
u32 bg_control = read_ioreg(REG_BGxCNT(layer));
u32 map_size = (bg_control >> 14) & 0x03;
u32 map_width = map_widths[map_size];
u32 horizontal_offset =
@ -2532,7 +2536,7 @@ void render_scanline_affine_##combine_op##_##alpha_op(u32 layer, \
u32 start, u32 end, void *scanline) \
{ \
render_scanline_extra_variables_##combine_op##_##alpha_op(affine); \
u32 bg_control = read_ioreg(REG_BG0CNT + layer); \
u32 bg_control = read_ioreg(REG_BGxCNT(layer)); \
u32 current_pixel; \
s32 source_x, source_y; \
u32 pixel_x, pixel_y; \
@ -3141,6 +3145,12 @@ static const u32 obj_width_table[] =
static const u32 obj_height_table[] =
{ 8, 16, 32, 64, 8, 8, 16, 32, 16, 32, 32, 64 };
static const u8 obj_dim_table[3][4][2] = {
{ {8, 8}, {16, 16}, {32, 32}, {64, 64} },
{ {16, 8}, {32, 8}, {32, 16}, {64, 32} },
{ {8, 16}, {8, 32}, {16, 32}, {32, 64} }
};
static u8 obj_priority_list[5][160][128];
static u8 obj_priority_count[5][160];
static u8 obj_alpha_count[160];
@ -3344,83 +3354,92 @@ render_scanline_obj_builder(copy, copy_tile, 2D, no_partial_alpha);
render_scanline_obj_builder(copy, copy_bitmap, 1D, no_partial_alpha);
render_scanline_obj_builder(copy, copy_bitmap, 2D, no_partial_alpha);
#define OBJ_MOD_NORMAL 0
#define OBJ_MOD_SEMITRAN 1
#define OBJ_MOD_WINDOW 2
#define OBJ_MOD_INVALID 3
// Goes through the object list in the OAM (from #127 to #0) and adds objects
// into a sorted list by priority for the current row.
// Invisible objects are discarded.
static void order_obj(u32 video_mode)
{
s32 obj_num, row;
s32 obj_x, obj_y;
u32 obj_size, obj_mode;
s32 obj_width, obj_height;
u32 obj_priority;
u32 obj_attribute_0, obj_attribute_1, obj_attribute_2;
u16 *oam_ptr = oam_ram + 508;
s32 obj_num;
u32 row;
t_oam *oam_base = (t_oam*)oam_ram;
memset(obj_priority_count, 0, sizeof(obj_priority_count));
memset(obj_alpha_count, 0, sizeof(obj_alpha_count));
for(obj_num = 127; obj_num >= 0; obj_num--, oam_ptr -= 4)
for(obj_num = 127; obj_num >= 0; obj_num--)
{
obj_attribute_0 = eswap16(oam_ptr[0]);
obj_attribute_2 = eswap16(oam_ptr[2]);
obj_size = obj_attribute_0 & 0xC000;
obj_priority = (obj_attribute_2 >> 10) & 0x03;
obj_mode = (obj_attribute_0 >> 10) & 0x03;
t_oam *oam_ptr = &oam_base[obj_num];
u16 obj_attr0 = eswap16(oam_ptr->attr0);
// Bit 9 disables regular sprites. Used as double bit for affine ones.
bool visible = (obj_attr0 & 0x0300) != 0x0200;
if (visible) {
u16 obj_shape = obj_attr0 >> 14;
u32 obj_mode = (obj_attr0 >> 10) & 0x03;
if(((obj_attribute_0 & 0x0300) != 0x0200) && (obj_size != 0xC000) &&
(obj_mode != 3) && ((video_mode < 3) ||
((obj_attribute_2 & 0x3FF) >= 512)))
{
obj_y = obj_attribute_0 & 0xFF;
if(obj_y > 160)
obj_y -= 256;
// Prohibited shape and mode
bool invalid = (obj_shape == 0x3) || (obj_mode == OBJ_MOD_INVALID);
if (!invalid) {
u16 obj_attr1 = eswap16(oam_ptr->attr1);
u16 obj_attr2 = eswap16(oam_ptr->attr2);
u32 obj_priority = (obj_attr2 >> 10) & 0x03;
obj_attribute_1 = eswap16(oam_ptr[1]);
obj_size = ((obj_size >> 12) & 0x0C) | (obj_attribute_1 >> 14);
obj_height = obj_height_table[obj_size];
obj_width = obj_width_table[obj_size];
if(obj_attribute_0 & 0x200)
{
obj_height *= 2;
obj_width *= 2;
}
if(((obj_y + obj_height) > 0) && (obj_y < 160))
{
obj_x = (s32)(obj_attribute_1 << 23) >> 23;
if(((obj_x + obj_width) > 0) && (obj_x < 240))
if (((video_mode < 3) || ((obj_attr2 & 0x3FF) >= 512)))
{
if(obj_y < 0)
// Calculate object size (from size and shape attr bits)
u16 obj_size = (obj_attr1 >> 14);
s32 obj_height = obj_dim_table[obj_shape][obj_size][1];
s32 obj_width = obj_dim_table[obj_shape][obj_size][0];
s32 obj_y = obj_attr0 & 0xFF;
if(obj_y > 160)
obj_y -= 256;
// Double size for affine sprites with double bit set
if(obj_attr0 & 0x200)
{
obj_height += obj_y;
obj_y = 0;
obj_height *= 2;
obj_width *= 2;
}
if((obj_y + obj_height) >= 160)
obj_height = 160 - obj_y;
if(obj_mode == 1)
if(((obj_y + obj_height) > 0) && (obj_y < 160))
{
for(row = obj_y; row < obj_y + obj_height; row++)
{
u32 cur_cnt = obj_priority_count[obj_priority][row];
obj_priority_list[obj_priority][row][cur_cnt] = obj_num;
obj_priority_count[obj_priority][row] = cur_cnt + 1;
obj_alpha_count[row] = 1;
}
}
else
{
if(obj_mode == 2)
obj_priority = 4;
s32 obj_x = (s32)(obj_attr1 << 23) >> 23;
for(row = obj_y; row < obj_y + obj_height; row++)
if(((obj_x + obj_width) > 0) && (obj_x < 240))
{
u32 cur_cnt = obj_priority_count[obj_priority][row];
obj_priority_list[obj_priority][row][cur_cnt] = obj_num;
obj_priority_count[obj_priority][row] = cur_cnt + 1;
// Clip Y coord and height to the 0..159 interval
u32 starty = MAX(obj_y, 0);
u32 endy = MIN(obj_y + obj_height, 160);
switch (obj_mode) {
case OBJ_MOD_SEMITRAN:
for(row = starty; row < endy; row++)
{
u32 cur_cnt = obj_priority_count[obj_priority][row];
obj_priority_list[obj_priority][row][cur_cnt] = obj_num;
obj_priority_count[obj_priority][row] = cur_cnt + 1;
// Mark the row as having semi-transparent objects
obj_alpha_count[row] = 1;
}
break;
case OBJ_MOD_WINDOW:
obj_priority = 4;
/* fallthrough */
case OBJ_MOD_NORMAL:
// Add the object to the list.
for(row = starty; row < endy; row++)
{
u32 cur_cnt = obj_priority_count[obj_priority][row];
obj_priority_list[obj_priority][row][cur_cnt] = obj_num;
obj_priority_count[obj_priority][row] = cur_cnt + 1;
}
break;
};
}
}
}
@ -3432,29 +3451,31 @@ static void order_obj(u32 video_mode)
u32 layer_order[16];
u32 layer_count;
static void order_layers(u32 layer_flags)
// Sorts active BG/OBJ layers and generates an ordered list of layers.
// Things are drawn back to front, so lowest priority goes first.
static void order_layers(u32 layer_flags, u32 vcnt)
{
s32 priority, layer_number;
bool obj_enabled = (layer_flags & 0x10);
s32 priority;
layer_count = 0;
for(priority = 3; priority >= 0; priority--)
{
for(layer_number = 3; layer_number >= 0; layer_number--)
bool anyobj = obj_priority_count[priority][vcnt] > 0;
s32 lnum;
for(lnum = 3; lnum >= 0; lnum--)
{
if(((layer_flags >> layer_number) & 1) &&
((read_ioreg(REG_BG0CNT + layer_number) & 0x03) == priority))
if(((layer_flags >> lnum) & 1) &&
((read_ioreg(REG_BGxCNT(lnum)) & 0x03) == priority))
{
layer_order[layer_count] = layer_number;
layer_count++;
layer_order[layer_count++] = lnum;
}
}
if((obj_priority_count[priority][read_ioreg(REG_VCOUNT)] > 0)
&& (layer_flags & 0x10))
{
layer_order[layer_count] = priority | 0x04;
layer_count++;
}
if(obj_enabled && anyobj)
layer_order[layer_count++] = priority | 0x04;
}
}
@ -4448,7 +4469,16 @@ static void render_scanline_window_##type(u16 *scanline, u32 dispcnt) \
render_scanline_window_builder(tile);
render_scanline_window_builder(bitmap);
static const u32 active_layers[6] = { 0x1F, 0x17, 0x1C, 0x14, 0x14, 0x14 };
static const u8 active_layers[] = {
0x1F, // Mode 0, Tile BG0-3 and OBJ
0x17, // Mode 1, Tile BG0-2 and OBJ
0x1C, // Mode 2, Tile BG2-3 and OBJ
0x14, // Mode 3, BMP BG2 and OBJ
0x14, // Mode 4, BMP BG2 and OBJ
0x14, // Mode 5, BMP BG2 and OBJ
0, // Unused
0,
};
void update_scanline(void)
{
@ -4466,7 +4496,7 @@ void update_scanline(void)
reg[OAM_UPDATED] = 0;
}
order_layers((dispcnt >> 8) & active_layers[video_mode]);
order_layers((dispcnt >> 8) & active_layers[video_mode], vcount);
if(skip_next_frame)
return;