Pokemon-Gen3-to-Gen-X/source/sprite_handler.c
2023-04-09 01:27:03 +02:00

440 lines
14 KiB
C

#include "base_include.h"
#include "sprite_handler.h"
#include "graphics_handler.h"
#include "print_system.h"
#include "config_settings.h"
#include <stddef.h>
#include "sprite_cursor_bin.h"
#include "item_icon_bin.h"
#include "sprite_palettes_bin.h"
#include "item_icon_palette_bin.h"
#define CPUFASTSET_FILL (0x1000000)
#define ITEM_ICON_INC_X ((POKEMON_SPRITE_X_TILES-ITEM_SPRITE_X_TILES)<<3)
#define ITEM_ICON_INC_Y ((POKEMON_SPRITE_Y_TILES-ITEM_SPRITE_Y_TILES)<<3)
#define SPRITE_BASE_SIZE_MULTIPLIER NUM_POKEMON_SPRITES
#define SPRITE_BASE_TILE_SIZE (POKEMON_SPRITE_Y_TILES*POKEMON_SPRITE_X_TILES)
#define SPRITE_TILE_SIZE (SPRITE_BASE_SIZE_MULTIPLIER*SPRITE_BASE_TILE_SIZE)
#define SPRITE_ALT_DISTANCE (SPRITE_BASE_TILE_SIZE*TILE_SIZE)
#define CURSOR_SPRITE_PALETTE_INDEX 9
#define SPRITE_SIZE (SPRITE_BASE_SIZE_MULTIPLIER*SPRITE_ALT_DISTANCE)
#define OVRAM_SIZE 0x8000
#define OVRAM_END (OVRAM_START+OVRAM_SIZE)
#ifdef __NDS__
#define OVRAM_END_SUB (OVRAM_START_SUB+OVRAM_SIZE)
#endif
#define POSSIBLE_SPRITES (OVRAM_SIZE/SPRITE_SIZE)
#define OAM_ENTITIES 0x80
#define OAM_DATA ((OBJATTR *)OAM)
#ifdef __NDS__
#define OAM_DATA_SUB ((OBJATTR *)OAM_SUB)
#endif
#define DISABLE_SPRITE (1<<9)
#define OFF_SCREEN_SPRITE SCREEN_HEIGHT
u8 check_for_same_address(const u8*);
uintptr_t get_vram_pos(void);
#ifdef __NDS__
uintptr_t get_vram_pos_sub(void);
#endif
void set_updated_shadow_oam(void);
void inc_inner_sprite_counter(void);
u8 get_sprite_counter(void);
void inc_sprite_counter(void);
void set_attributes(u16, u16, u16);
u8 get_first_variable_palette(void);
u8 get_3bpp_palette(int);
void set_palette_3bpp(u8*, int, int);
u16 get_item_icon_tile(void);
u16 get_mail_icon_tile(void);
void set_item_icon(u16, u16);
void set_mail_icon(u16, u16);
void raw_update_cursor_x(u16);
const u16* sprite_cursor_gfx = (const u16*)sprite_cursor_bin;
const u16* item_icon_gfx = (const u16*)item_icon_bin;
const u16* sprite_palettes_bin_16 = (const u16*)sprite_palettes_bin;
const u16* item_icon_palette_bin_16 = (const u16*)item_icon_palette_bin;
u8 __sprite_counter;
u8 __inner_sprite_counter;
u8 __party_sprite_counter;
u8 __party_inner_sprite_counter;
u8 cursor_sprite;
u8 inner_cursor_sprite;
u16 cursor_base_x;
const u8* sprite_pointers[POSSIBLE_SPRITES];
u8 updated_shadow_oam;
u8 loaded_inner_sprite_counter;
u16 loaded_cursor_base_x;
OBJATTR shadow_oam[OAM_ENTITIES];
void init_sprite_counter(){
__sprite_counter = 0;
__inner_sprite_counter = 0;
loaded_inner_sprite_counter = 0;
loaded_cursor_base_x = 0;
}
void set_updated_shadow_oam() {
wait_for_vblank_if_needed();
updated_shadow_oam = 1;
}
IWRAM_CODE void update_normal_oam() {
if(updated_shadow_oam) {
u32* oam_ptr = (u32*)OAM_DATA;
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
u32* oam_ptr_sub = (u32*)OAM_DATA_SUB;
#endif
u32* shadow_oam_ptr = (u32*)shadow_oam;
for(size_t i = 0; i < ((sizeof(OBJATTR)*OAM_ENTITIES)>>2); i++) {
oam_ptr[i] = shadow_oam_ptr[i];
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
oam_ptr_sub[i] = shadow_oam_ptr[i];
#endif
}
updated_shadow_oam = 0;
}
loaded_inner_sprite_counter = __inner_sprite_counter;
loaded_cursor_base_x = cursor_base_x;
}
void set_party_sprite_counter(){
__party_sprite_counter = __sprite_counter;
__party_inner_sprite_counter = __inner_sprite_counter;
}
void enable_sprites_rendering(){
REG_DISPCNT |= OBJ_ON | OBJ_1D_MAP;
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
REG_DISPCNT_SUB |= OBJ_ON | OBJ_1D_MAP;
#endif
}
void disable_sprites_rendering(){
REG_DISPCNT &= ~(OBJ_ON);
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
REG_DISPCNT_SUB &= ~(OBJ_ON);
#endif
}
void init_sprites(){
reset_sprites(0);
update_normal_oam();
}
u8 get_sprite_counter(){
return __sprite_counter;
}
void inc_sprite_counter(){
__sprite_counter++;
__inner_sprite_counter++;
}
void inc_inner_sprite_counter(){
__inner_sprite_counter++;
}
u8 get_next_sprite_index(){
return __inner_sprite_counter;
}
u8 get_first_variable_palette(){
return ((sprite_palettes_bin_size + item_icon_palette_bin_size)>>5);
}
uintptr_t get_vram_pos(){
uintptr_t vram_pos = OVRAM_START+(__sprite_counter*SPRITE_SIZE);
if(vram_pos >= OVRAM_END)
vram_pos = OVRAM_END - SPRITE_SIZE;
return vram_pos;
}
#ifdef __NDS__
uintptr_t get_vram_pos_sub(){
uintptr_t vram_pos = OVRAM_START_SUB+(__sprite_counter*SPRITE_SIZE);
if(vram_pos >= OVRAM_END_SUB)
vram_pos = OVRAM_END_SUB - SPRITE_SIZE;
return vram_pos;
}
#endif
u8 get_3bpp_palette(int index) {
return (index>>1) + get_first_variable_palette();
}
void set_palette_3bpp(u8* colors, int index, int palette) {
u8 new_palette = get_3bpp_palette(index);
const u8 num_colors = 1<<3;
const u8 base = num_colors*(index & 1);
for(int i = 0; i < num_colors; i++) {
if(i)
SPRITE_PALETTE[base+i+(new_palette<<4)] = SPRITE_PALETTE[colors[i]+(palette<<4)];
else
SPRITE_PALETTE[i+(new_palette<<4)] = SPRITE_PALETTE[colors[i]+(palette<<4)];
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
if(i)
SPRITE_PALETTE_SUB[base+i+(new_palette<<4)] = SPRITE_PALETTE_SUB[colors[i]+(palette<<4)];
else
SPRITE_PALETTE_SUB[i+(new_palette<<4)] = SPRITE_PALETTE_SUB[colors[i]+(palette<<4)];
#endif
}
}
void init_cursor(){
sprite_pointers[__sprite_counter] = (const u8*)sprite_cursor_gfx;
for(int i = 0; i < SPRITE_BASE_SIZE_MULTIPLIER; i++) {
u16* vram_pos = (u16*)(get_vram_pos() + (SPRITE_ALT_DISTANCE*i));
for(size_t j = 0; j < (sprite_cursor_bin_size>>1); j++)
vram_pos[j] = sprite_cursor_gfx[j];
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
vram_pos = (u16*)(get_vram_pos_sub() + (SPRITE_ALT_DISTANCE*i));
for(size_t j = 0; j < (sprite_cursor_bin_size>>1); j++)
vram_pos[j] = sprite_cursor_gfx[j];
#endif
}
for(int i = 0; i < TOTAL_BG; i++) {
set_attributes(OFF_SCREEN_SPRITE, 0, (SPRITE_TILE_SIZE*__sprite_counter) | ((3-i)<<10) | ((sprite_palettes_bin_size>>5)<<12));
if(i < TOTAL_BG-1)
inc_inner_sprite_counter();
}
cursor_sprite = __sprite_counter;
inner_cursor_sprite = __inner_sprite_counter;
update_cursor_base_x(0);
inc_sprite_counter();
}
void set_cursor_palette() {
SPRITE_PALETTE[(sprite_palettes_bin_size>>1)+CURSOR_SPRITE_PALETTE_INDEX] = get_full_colour(SPRITE_COLOUR_POS);
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
SPRITE_PALETTE_SUB[(sprite_palettes_bin_size>>1)+CURSOR_SPRITE_PALETTE_INDEX] = get_full_colour(SPRITE_COLOUR_POS);
#endif
}
void init_oam_palette(){
for(size_t i = 0; i < (sprite_palettes_bin_size>>1); i++)
SPRITE_PALETTE[i] = sprite_palettes_bin_16[i];
for(size_t i = 0; i < (item_icon_palette_bin_size>>1); i++)
SPRITE_PALETTE[i+(sprite_palettes_bin_size>>1)] = item_icon_palette_bin_16[i];
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
for(size_t i = 0; i < (sprite_palettes_bin_size>>1); i++)
SPRITE_PALETTE_SUB[i] = sprite_palettes_bin_16[i];
for(size_t i = 0; i < (item_icon_palette_bin_size>>1); i++)
SPRITE_PALETTE_SUB[i+(sprite_palettes_bin_size>>1)] = item_icon_palette_bin_16[i];
#endif
set_cursor_palette();
}
void init_item_icon(){
for(int i = 0; i < SPRITE_BASE_SIZE_MULTIPLIER; i++) {
u16* vram_pos = (u16*)(get_vram_pos() + sprite_cursor_bin_size + (SPRITE_ALT_DISTANCE*i));
for(size_t j = 0; j < (item_icon_bin_size>>1); j++)
vram_pos[j] = item_icon_gfx[j];
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
vram_pos = (u16*)(get_vram_pos_sub() + sprite_cursor_bin_size + (SPRITE_ALT_DISTANCE*i));
for(size_t j = 0; j < (item_icon_bin_size>>1); j++)
vram_pos[j] = item_icon_gfx[j];
#endif
}
}
u16 get_item_icon_tile(){
return (SPRITE_TILE_SIZE*cursor_sprite) + (sprite_cursor_bin_size>>5);
}
u16 get_mail_icon_tile(){
return get_item_icon_tile() + 1;
}
void set_item_icon(u16 y, u16 x){
set_attributes((y + ITEM_ICON_INC_Y) & 0xFF, (x + ITEM_ICON_INC_X) & 0xFF, get_item_icon_tile() | (get_curr_priority()<<10) | ((sprite_palettes_bin_size>>5)<<12));
inc_inner_sprite_counter();
}
void set_mail_icon(u16 y, u16 x){
set_attributes((y + ITEM_ICON_INC_Y) & 0xFF, (x + ITEM_ICON_INC_X) & 0xFF, get_mail_icon_tile() | (get_curr_priority()<<10) | ((sprite_palettes_bin_size>>5)<<12));
inc_inner_sprite_counter();
}
u8 check_for_same_address(const u8* address){
u8 limit = __sprite_counter;
if(__sprite_counter > POSSIBLE_SPRITES)
limit = POSSIBLE_SPRITES;
for(int i = 0; i < limit; i++)
if(sprite_pointers[i] == address)
return i;
return POSSIBLE_SPRITES;
}
void set_pokemon_sprite(const u8* address, u8 palette, u8 info, u8 display_item, u8 display_mail, u16 y, u16 x){
set_updated_shadow_oam();
if(display_mail)
set_mail_icon(y, x);
else if(display_item)
set_item_icon(y, x);
u8 is_3bpp = info&2;
u8 zero_fill = info&1;
u8 position = check_for_same_address(address);
if(position == POSSIBLE_SPRITES) {
u8 colors[8];
load_pokemon_sprite_gfx((const u32*)address, (u32*)get_vram_pos(), is_3bpp, zero_fill, __sprite_counter-(cursor_sprite+1), colors);
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
load_pokemon_sprite_gfx((const u32*)address, (u32*)get_vram_pos_sub(), is_3bpp, zero_fill, __sprite_counter-(cursor_sprite+1), colors);
#endif
if(is_3bpp)
set_palette_3bpp(colors, __sprite_counter-(cursor_sprite+1), palette);
position = __sprite_counter;
__sprite_counter++;
}
if(is_3bpp)
palette = get_3bpp_palette(position-(cursor_sprite+1));
if(position < POSSIBLE_SPRITES)
sprite_pointers[position] = address;
set_attributes(y, x|ATTR1_SIZE_32, (SPRITE_TILE_SIZE*position)|(get_curr_priority()<<10)|(palette<<12));
inc_inner_sprite_counter();
}
void update_cursor_y(u16 cursor_y){
set_updated_shadow_oam();
shadow_oam[inner_cursor_sprite-get_curr_priority()].attr0 = cursor_y;
}
IWRAM_CODE void raw_update_cursor_x(u16 cursor_x){
OAM_DATA[inner_cursor_sprite-get_loaded_priority()].attr1 = cursor_x;
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
OAM_DATA_SUB[inner_cursor_sprite-get_loaded_priority()].attr1 = cursor_x;
#endif
shadow_oam[inner_cursor_sprite-get_loaded_priority()].attr1 = cursor_x;
}
IWRAM_CODE void raw_update_sprite_y(u8 index, u8 new_y){
if(index >= OAM_ENTITIES)
index = OAM_ENTITIES-1;
OAM_DATA[index].attr0 &= ~0xFF;
OAM_DATA[index].attr0 |= new_y;
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
OAM_DATA_SUB[index].attr0 &= ~0xFF;
OAM_DATA_SUB[index].attr0 |= new_y;
#endif
shadow_oam[index].attr0 &= ~0xFF;
shadow_oam[index].attr0 |= new_y;
}
IWRAM_CODE void fade_all_sprites_to_white(u16 fading_fraction){
REG_BLDCNT &= ~(3<<6);
REG_BLDCNT |= (1<<4) | (2<<6);
REG_BLDY = fading_fraction;
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
REG_BLDCNT_SUB &= ~(3<<6);
REG_BLDCNT_SUB |= (1<<4) | (2<<6);
REG_BLDY_SUB = fading_fraction;
#endif
}
IWRAM_CODE void remove_fade_all_sprites(){
REG_BLDCNT &= ~((1<<4) | (2<<6));
REG_BLDY = 0;
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
REG_BLDCNT_SUB &= ~((1<<4) | (2<<6));
REG_BLDY_SUB = 0;
#endif
}
void update_cursor_base_x(u16 cursor_x){
wait_for_vblank_if_needed();
cursor_base_x = cursor_x;
}
void disable_cursor(){
update_cursor_y(OFF_SCREEN_SPRITE);
}
void disable_all_cursors(){
set_updated_shadow_oam();
for(int i = 0; i < TOTAL_BG; i++)
shadow_oam[inner_cursor_sprite-i].attr0 = OFF_SCREEN_SPRITE;
}
void set_attributes(u16 obj_attr_0, u16 obj_attr_1, u16 obj_attr_2) {
set_updated_shadow_oam();
u8 position = __inner_sprite_counter;
if(__inner_sprite_counter >= OAM_ENTITIES)
position = OAM_ENTITIES-1;
shadow_oam[position].attr0 = obj_attr_0;
shadow_oam[position].attr1 = obj_attr_1;
shadow_oam[position].attr2 = obj_attr_2;
}
void reset_sprites_to_cursor(u8 reset_ovram){
wait_for_vblank_if_needed();
if(reset_ovram)
__sprite_counter = cursor_sprite+1;
__inner_sprite_counter = inner_cursor_sprite+1;
reset_sprites(__inner_sprite_counter);
}
void reset_sprites(u8 start){
set_updated_shadow_oam();
for(int i = start; i < OAM_ENTITIES; i++) {
shadow_oam[i].attr0 = OFF_SCREEN_SPRITE;
shadow_oam[i].attr1 = 0;
shadow_oam[i].attr2 = 0;
}
}
void disable_all_sprites(){
set_updated_shadow_oam();
for(int i = 0; i < OAM_ENTITIES; i++)
shadow_oam[i].attr0 |= DISABLE_SPRITE;
}
void enable_all_sprites(){
set_updated_shadow_oam();
for(int i = 0; i < OAM_ENTITIES; i++)
shadow_oam[i].attr0 &= ~DISABLE_SPRITE;
}
void reset_sprites_to_party(){
wait_for_vblank_if_needed();
__sprite_counter = __party_sprite_counter;
__inner_sprite_counter = __party_inner_sprite_counter;
reset_sprites(__party_inner_sprite_counter);
}
IWRAM_CODE void move_sprites(u8 counter){
u8 counter_kind = counter & 8;
u8 limit = loaded_inner_sprite_counter;
if(loaded_inner_sprite_counter > OAM_ENTITIES)
limit = OAM_ENTITIES;
for(int i = inner_cursor_sprite+1; i < limit; i++) {
u16 obj_attr_2 = OAM_DATA[i].attr2 & ~SPRITE_BASE_TILE_SIZE;
if(counter_kind)
obj_attr_2 |= SPRITE_BASE_TILE_SIZE;
OAM_DATA[i].attr2 = obj_attr_2;
#if defined (__NDS__) && (SAME_ON_BOTH_SCREENS)
obj_attr_2 = OAM_DATA_SUB[i].attr2 & ~SPRITE_BASE_TILE_SIZE;
if(counter_kind)
obj_attr_2 |= SPRITE_BASE_TILE_SIZE;
OAM_DATA_SUB[i].attr2 = obj_attr_2;
#endif
}
}
IWRAM_CODE void move_cursor_x(u8 counter){
counter = counter & 0x3F;
u8 pos = counter >> 3;
if(pos > 4)
pos = 8-pos;
raw_update_cursor_x(loaded_cursor_base_x + pos);
}