Kind of optimize sprites for space

Enabled stripping of top row when always empty (all pokemon but smoochum). Did not enable 3bpp. It would save 7 KBs extra, but it's extremely slow...
This commit is contained in:
Lorenzo Carletti 2022-12-29 22:49:18 +01:00
parent 8ff3741c83
commit 08bde102bd
9 changed files with 74 additions and 243 deletions

Binary file not shown.

1
data/sprites_info.bin Normal file
View File

@ -0,0 +1 @@
UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUEUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU

BIN
data_raw/sprites_uncmp.bin Normal file

Binary file not shown.

View File

@ -1,211 +0,0 @@
import usb.core
import usb.util
import signal
import sys
import traceback
import time
import os
dev = None
sleep_timer = 0.01
sram_transfer_val = 2
rom_transfer_val = 1
rom_bank_size = 0x40
rom_banks = [2,4,8,16,32,64,128,256,512,0,0,0,0,0,0,0,0,0,72,80,96]
sram_banks_sizes = [0,8,0x20,0x20,0x20,0x20,2]
sram_banks = [0,1,1,4,16,8,1]
section_size = 0x100
normal_nybble = 0x10
check_nybble = 0x40
def rom_transfer(data, transfer_size):
print("Starting ROM dump...")
size = rom_bank_size
banks = rom_banks[transfer_size]
return transfer_bank(data, size, banks)
def sram_transfer(data, transfer_size):
print("Starting SRAM dump...")
size = sram_banks_sizes[transfer_size]
banks = sram_banks[transfer_size]
return transfer_bank(data, size, banks)
def transfer_bank(data, size, banks):
if(banks == 0):
print("Nothing to dump!")
return None
res = []
for i in range(banks):
print("Bank " + str(i+ 1) + " out of " + str(banks) + "!")
for j in range(size):
print("Section " + str(j+ 1) + " out of " + str(size) + "!")
res += read_section(data)
return res
def read_section(data):
buf = []
checked = False
half = False
while(not checked):
for i in range(2):
accepted = False
while not accepted:
sleep_func()
sendByte(data[i])
recv = receiveByte()
high_recv = recv & 0xF0
if(high_recv == check_nybble or high_recv == normal_nybble):
#print("send: 0x%02x" % data[i])
#print("recv: 0x%02x" % recv)
if(high_recv == check_nybble):
if(half):
checked = True
half = True
accepted = True
data[i] = recv & 0xF;
#else:
#print("BAD RECV: 0x%02x" % recv)
val = (data[1] | (data[0] << 4))
if(checked):
if(val == 0):
checked = False
buf = []
else:
buf += [val]
#print("Data: 0x%02x" % val)
if(half):
# Handle a "nybble" desync
sleep_func()
sendByte(data[0])
recv = receiveByte()
half = False
return buf[0:len(buf)-1] # There is an extra transfer in order to ensure the last byte is correct. Discard it
def transfer_func():
print("Waiting for the transfer to start...")
data = [0,0]
buf = read_section(data) # Read the starting information
if(len(buf) > 2):
print("The transfer was previously interrupted. Please reset the GameBoy!")
return
transfer_type = buf[0]
transfer_size = buf[1]
if(transfer_type == rom_transfer_val):
res = rom_transfer(data, transfer_size)
elif(transfer_type == sram_transfer_val):
res = sram_transfer(data, transfer_size)
if res is not None:
if(len(sys.argv) > 1):
target = sys.argv[1]
else:
target = input("Please enter where to save the dump: ")
newFile = open(target, "wb")
newFile.write(bytearray(res))
newFile.close()
return
# Function needed in order to make sure there is enough time for the slave to prepare the next byte.
def sleep_func():
time.sleep(sleep_timer)
# Code dependant on this connection method
def sendByte(byte_to_send):
epOut.write(byte_to_send.to_bytes(1, byteorder='big'))
return
def receiveByte():
return int.from_bytes(epIn.read(epIn.wMaxPacketSize, 100), byteorder='big')
# Things for the USB connection part
def exit_gracefully():
if dev is not None:
usb.util.dispose_resources(dev)
if(os.name != "nt"):
if reattach:
dev.attach_kernel_driver(0)
print('Done.')
def signal_handler(sig, frame):
print('You pressed Ctrl+C!')
exit_gracefully()
signal.signal(signal.SIGINT, signal_handler)
# The execution path
try:
devices = list(usb.core.find(find_all=True,idVendor=0xcafe, idProduct=0x4011))
for d in devices:
#print('Device: %s' % d.product)
dev = d
if dev is None:
raise ValueError('Device not found')
reattach = False
if(os.name != "nt"):
if dev.is_kernel_driver_active(0):
try:
reattach = True
dev.detach_kernel_driver(0)
print("kernel driver detached")
except usb.core.USBError as e:
sys.exit("Could not detach kernel driver: %s" % str(e))
else:
print("no kernel driver attached")
dev.reset()
dev.set_configuration()
cfg = dev.get_active_configuration()
#print('Configuration: %s' % cfg)
intf = cfg[(2,0)] # Or find interface with class 0xff
#print('Interface: %s' % intf)
epIn = usb.util.find_descriptor(
intf,
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_IN)
assert epIn is not None
#print('EP In: %s' % epIn)
epOut = usb.util.find_descriptor(
intf,
# match the first OUT endpoint
custom_match = \
lambda e: \
usb.util.endpoint_direction(e.bEndpointAddress) == \
usb.util.ENDPOINT_OUT)
assert epOut is not None
#print('EP Out: %s' % epOut)
# Control transfer to enable webserial on device
#print("control transfer out...")
dev.ctrl_transfer(bmRequestType = 1, bRequest = 0x22, wIndex = 2, wValue = 0x01)
transfer_func()
exit_gracefully()
except:
#traceback.print_exc()
print("Unexpected exception: ", sys.exc_info()[0])
exit_gracefully()

View File

@ -3,23 +3,55 @@
#include "gender_symbols_bin.h"
#define MAX_SIZE_POKEMON_SPRITE 0x400
#define GRAPHICS_BUFFER_SHIFT 10
#define GRAPHICS_BUFFER_SIZE (1 << GRAPHICS_BUFFER_SHIFT)
#define CPUFASTSET_FILL (0x1000000)
void init_gender_symbols(){
u8 colors[] = {0,1};
convert_1bpp(gender_symbols_bin, (u32*)(VRAM+(0x88<<5)), gender_symbols_bin_size, colors, 1);
}
void load_pokemon_sprite_gfx(u32 src, u32 dst, u8 info){
u8 is_3bpp = info&2;
u8 zero_fill = info&1;
u32 zero = 0;
u32 buffer[2][MAX_SIZE_POKEMON_SPRITE>>2];
LZ77UnCompWram(src, buffer[0]);
if(is_3bpp) {
u8 colors[8];
for(int i = 0; i < 8; i++)
colors[i] = (buffer[0][0]>>(4*i))&0xF;
if(zero_fill) {
CpuFastSet(&zero, buffer[1], (MAX_SIZE_POKEMON_SPRITE>>2)|CPUFASTSET_FILL);
convert_3bpp(buffer[0]+1, (u32*)(((u32)buffer[1])+0x80), (((MAX_SIZE_POKEMON_SPRITE>>2)*3)>>1)-0x60, colors, 0);
convert_3bpp(buffer[0]+1+(((((MAX_SIZE_POKEMON_SPRITE>>2)*3)>>1)-0x60)>>2), (u32*)(((u32)buffer[1])+0x280), (((MAX_SIZE_POKEMON_SPRITE>>2)*3)>>1)-0x60, colors, 0);
CpuFastSet(buffer[1], dst, (MAX_SIZE_POKEMON_SPRITE>>2));
}
else
convert_3bpp(buffer[0]+1, dst, (MAX_SIZE_POKEMON_SPRITE>>2)*3, colors, 0);
}
else {
if(zero_fill) {
CpuFastSet(&zero, buffer[1], (MAX_SIZE_POKEMON_SPRITE>>2)|CPUFASTSET_FILL);
CpuFastSet(buffer[0], ((u32)buffer[1])+0x80, ((MAX_SIZE_POKEMON_SPRITE>>1)-0x80)>>2);
CpuFastSet(buffer[0]+(((MAX_SIZE_POKEMON_SPRITE>>1)-0x80)>>2), ((u32)buffer[1])+0x280, ((MAX_SIZE_POKEMON_SPRITE>>1)-0x80)>>2);
CpuFastSet(buffer[1], dst, (MAX_SIZE_POKEMON_SPRITE>>2));
}
else
CpuFastSet(buffer[0], dst, MAX_SIZE_POKEMON_SPRITE>>2);
}
}
void convert_xbpp(u8* src, u32* dst, u16 src_size, u8* colors, u8 is_forward, u8 num_bpp) {
const u16 buffer_size = GRAPHICS_BUFFER_SIZE>>2;
u32 buffer[buffer_size];
if(num_bpp == 0 || num_bpp > 4)
return;
const u16 limit = buffer_size-1;
u16 base = 0;
u16 num_rows = Div(src_size, num_bpp);
if(DivMod(src_size, 8*num_bpp))
if(DivMod(src_size, num_bpp))
num_rows += 1;
for(int i = 0; i < num_rows; i++) {
u32 src_data = 0;
@ -31,15 +63,8 @@ void convert_xbpp(u8* src, u32* dst, u16 src_size, u8* colors, u8 is_forward, u8
row |= (colors[(src_data>>(num_bpp*j))&((1<<num_bpp)-1)]&0xF) << (4*j);
else
row |= (colors[(src_data>>(num_bpp*j))&((1<<num_bpp)-1)]&0xF) << (4*(7-j));
buffer[i-base] = row;
if((i-base) == limit) {
CpuFastSet(buffer, dst + (base<<2), buffer_size);
base += buffer_size;
}
dst[i] = row;
}
u16 remaining = num_rows-base;
if(remaining)
CpuFastSet(buffer, dst + (base<<2), remaining);
}
void convert_1bpp(u8* src, u32* dst, u16 src_size, u8* colors, u8 is_forward) {

View File

@ -3,6 +3,8 @@
void init_gender_symbols();
void load_pokemon_sprite_gfx(u32, u32, u8);
void convert_xbpp(u8*, u32*, u16, u8*, u8, u8);
void convert_1bpp(u8*, u32*, u16, u8*, u8);
void convert_2bpp(u8*, u32*, u16, u8*, u8);

View File

@ -118,6 +118,8 @@ void start_gen2_slave(void)
#define E_MAIN_GAME_CODE 0x2
#define E_SUB_GAME_CODE 0x0
#define VALID_MAPS 36
#include "party_handler.h"
#include "text_handler.h"
#include "sprite_handler.h"
@ -131,6 +133,8 @@ const u16 pokedex_extra_pos_1 [] = {0x938, 0x5F8, 0x988};
const u16 pokedex_extra_pos_2 [] = {0xC0C, 0xB98, 0xCA4};
const u16 mail_pos [] = {0xC4C, 0xDD0, 0xCE0};
const u16 ribbon_pos [] = {0x290, 0x21C, 0x328};
const u16 special_area [] = {0, 9, 9};
const u16 rs_valid_maps[VALID_MAPS] = {0x0202, 0x0203, 0x0301, 0x0302, 0x0405, 0x0406, 0x0503, 0x0504, 0x0603, 0x0604, 0x0700, 0x0701, 0x0804, 0x0805, 0x090a, 0x090b, 0x0a05, 0x0a06, 0x0b05, 0x0b06, 0x0c02, 0x0c03, 0x0d06, 0x0d07, 0x0e03, 0x0e04, 0x0f02, 0x0f03, 0x100c, 0x100d, 0x100a, 0x1918, 0x1919, 0x191a, 0x191b, 0x1a05};
u8 game_is_jp;
u8 game_main_version;
@ -785,6 +789,7 @@ int main(void)
returned_val = handle_input_main_menu(&cursor_y_pos, keys, &update, &target, &region, &master);
print_main_menu(update, target, region, master);
//print_pokemon_page1(update, 1, &parties_3[0].mons[0]);
//print_trade_menu(update, 2, 1);
update_cursor_y(BASE_Y_CURSOR_MAIN_MENU + (BASE_Y_CURSOR_INCREMENT_MAIN_MENU * cursor_y_pos));
if(returned_val == START_MULTIBOOT) {
curr_state = MULTIBOOT;

View File

@ -2,6 +2,26 @@
#include "party_handler.h"
#include "text_handler.h"
#include "sprite_handler.h"
#include "graphics_handler.h"
#include "pokemon_moves_pp_gen1_bin.h"
#include "pokemon_moves_pp_bin.h"
#include "pokemon_gender_bin.h"
#include "pokemon_names_bin.h"
#include "item_names_bin.h"
#include "gen2_names_jap_bin.h"
#include "sprites_cmp_bin.h"
#include "sprites_info_bin.h"
#include "palettes_references_bin.h"
#include "item_gen3_to_12_bin.h"
#include "gen3_to_1_conv_table_bin.h"
#include "gen1_to_3_conv_table_bin.h"
#include "pokemon_exp_groups_bin.h"
#include "exp_table_bin.h"
#include "pokemon_stats_bin.h"
#include "pokemon_stats_gen1_bin.h"
#include "pokemon_types_gen1_bin.h"
#include "pokemon_natures_bin.h"
u8 decrypt_data(struct gen3_mon*, u32*);
u8 is_egg_gen3(struct gen3_mon*, struct gen3_mon_misc*);
@ -32,24 +52,7 @@ u8 gender_thresholds_gen12[] = {8, 0, 2, 4, 12, 14, 16, 17};
#define UNOWN_V_LETTER 21
#define INITIAL_MAIL_GEN3 121
#define LAST_MAIL_GEN3 132
const u8 pokemon_moves_pp_gen1_bin[];
const u8 pokemon_moves_pp_bin[];
const u8 pokemon_gender_bin[];
const u8 pokemon_names_bin[];
const u8 item_names_bin[];
const u8 gen2_names_international_bin[];
const u8 gen2_names_jap_bin[];
const u8 sprites_cmp_bin[];
const u8 palettes_references_bin[];
const u8 item_gen3_to_12_bin[];
const u8 gen3_to_1_conv_table_bin[];
const u8 gen1_to_3_conv_table_bin[];
const u8 pokemon_exp_groups_bin[];
const u8 exp_table_bin[];
const u8 pokemon_stats_bin[];
const u8 pokemon_stats_gen1_bin[];
const u8 pokemon_types_gen1_bin[];
const u8 pokemon_natures_bin[];
const struct exp_level* exp_table = (const struct exp_level*)exp_table_bin;
const struct stats_gen_23* stats_table = (const struct stats_gen_23*)pokemon_stats_bin;
const struct stats_gen_1* stats_table_gen1 = (const struct stats_gen_1*)pokemon_stats_gen1_bin;
@ -184,6 +187,11 @@ const u8* get_pokemon_sprite_pointer(int index, u32 pid, u8 is_egg){
return get_table_pointer(sprites_cmp_bin, get_mon_index(index, pid, is_egg));
}
u8 get_pokemon_sprite_info(int index, u32 pid, u8 is_egg){
u16 mon_index = get_mon_index(index, pid, is_egg);
return (sprites_info_bin[mon_index>>2]>>(2*(mon_index&3)))&3;
}
u8 get_palette_references(int index, u32 pid, u8 is_egg){
return palettes_references_bin[get_mon_index(index, pid, is_egg)];
}
@ -192,7 +200,7 @@ void load_pokemon_sprite(int index, u32 pid, u8 is_egg, u8 has_item, u16 y, u16
u8 sprite_counter = get_sprite_counter();
u32 address = get_pokemon_sprite_pointer(index, pid, is_egg);
u8 palette = get_palette_references(index, pid, is_egg);
LZ77UnCompVram(address, get_vram_pos());
load_pokemon_sprite_gfx(address, get_vram_pos(), get_pokemon_sprite_info(index, pid, is_egg));
set_attributes(y, x |(1<<15), (32*sprite_counter)|(palette<<12));
inc_sprite_counter();
if(!is_egg && has_item)

View File

@ -4,6 +4,7 @@
#define OAM 0x7000000
#define BASE_CURSOR_X 2
#define BASE_CURSOR_Y 8
#define CPUFASTSET_FILL (0x1000000)
const u8 sprite_cursor_bin[];
const u32 sprite_cursor_bin_size;