mirror of
https://github.com/GearsProgress/Poke_Transporter_GB.git
synced 2026-09-11 18:45:38 -05:00
Move reading dialogue text out of the text_loop() to conserve IWRAM
This commit is contained in:
@@ -32,7 +32,12 @@ public:
|
||||
/**
|
||||
* This function returns a pointer to a text entry in the decompression_buffer
|
||||
*/
|
||||
const uint8_t* get_text_entry(uint8_t index) const;
|
||||
const uint8_t* get_text_entry(uint16_t index) const;
|
||||
|
||||
/**
|
||||
* This function returns the text entry size in bytes at the given index
|
||||
*/
|
||||
uint16_t get_text_entry_size(uint16_t index) const;
|
||||
private:
|
||||
uint8_t *decompression_buffer_;
|
||||
};
|
||||
@@ -66,7 +71,12 @@ public:
|
||||
/**
|
||||
* This function returns a pointer to a text entry in the decompression_buffer
|
||||
*/
|
||||
const uint8_t* get_text_entry(uint8_t index);
|
||||
const uint8_t* get_text_entry(uint16_t index);
|
||||
|
||||
/**
|
||||
* This function returns the text entry size in bytes at the given index
|
||||
*/
|
||||
uint16_t get_text_entry_size(uint16_t index) const;
|
||||
private:
|
||||
uint8_t* get_window_start() const;
|
||||
uint8_t* get_window_end() const;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "zx0_decompressor.h"
|
||||
#include <cstring>
|
||||
|
||||
static uint16_t get_entry_offset_by_index(const uint8_t *text_table, uint8_t index)
|
||||
static uint16_t get_entry_offset_by_index(const uint8_t *text_table, uint16_t index)
|
||||
{
|
||||
return *((uint16_t*)(text_table + 2 + index * 2));
|
||||
}
|
||||
@@ -13,6 +13,32 @@ static uint16_t get_entries_start_offset_of(uint8_t num_text_entries)
|
||||
return 2 + (num_text_entries * 2);
|
||||
}
|
||||
|
||||
static uint16_t get_num_text_entries(const uint8_t *index_buffer)
|
||||
{
|
||||
return *((uint16_t*)index_buffer);
|
||||
}
|
||||
|
||||
static uint16_t get_entry_size_in_bytes(const uint8_t *index_buffer, uint16_t index)
|
||||
{
|
||||
const uint16_t entry_offset = get_entry_offset_by_index(index_buffer, index);
|
||||
const uint16_t num_text_entries = get_num_text_entries(index_buffer);
|
||||
uint16_t entry_size_in_bytes;
|
||||
|
||||
if(index != num_text_entries - 1)
|
||||
{
|
||||
const uint16_t next_entry_offset = get_entry_offset_by_index(index_buffer, index + 1);
|
||||
entry_size_in_bytes = next_entry_offset - entry_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16_t entry_byte_offset = get_entries_start_offset_of(num_text_entries) + entry_offset;
|
||||
// we don't have a next entry. So we need to consider the end of the file
|
||||
const uint16_t decompressed_size = static_cast<uint16_t>(zx0_decompressor_get_decompressed_size());
|
||||
entry_size_in_bytes = decompressed_size - entry_byte_offset;
|
||||
}
|
||||
return entry_size_in_bytes;
|
||||
}
|
||||
|
||||
text_data_table::text_data_table(uint8_t *decompression_buffer)
|
||||
: decompression_buffer_(decompression_buffer)
|
||||
{
|
||||
@@ -26,15 +52,20 @@ void text_data_table::decompress(const uint8_t *compressed_table)
|
||||
|
||||
uint16_t text_data_table::get_number_of_text_entries() const
|
||||
{
|
||||
return *((uint16_t*)decompression_buffer_);
|
||||
return get_num_text_entries(decompression_buffer_);
|
||||
}
|
||||
|
||||
const uint8_t* text_data_table::get_text_entry(uint8_t index) const
|
||||
const uint8_t* text_data_table::get_text_entry(uint16_t index) const
|
||||
{
|
||||
const uint16_t entry_offset = get_entry_offset_by_index(decompression_buffer_, index);
|
||||
return decompression_buffer_ + get_entries_start_offset_of(get_number_of_text_entries()) + entry_offset;
|
||||
}
|
||||
|
||||
uint16_t text_data_table::get_text_entry_size(uint16_t index) const
|
||||
{
|
||||
return get_entry_size_in_bytes(decompression_buffer_, index);
|
||||
}
|
||||
|
||||
streamed_text_data_table::streamed_text_data_table(uint8_t *decompression_buffer, uint32_t decompression_buffer_size, uint8_t *index_buffer)
|
||||
: compressed_table_(nullptr)
|
||||
, decompression_buffer_(decompression_buffer)
|
||||
@@ -64,34 +95,20 @@ uint16_t streamed_text_data_table::get_number_of_text_entries() const
|
||||
return *((uint16_t*)index_buffer_);
|
||||
}
|
||||
|
||||
const uint8_t* streamed_text_data_table::get_text_entry(uint8_t index)
|
||||
const uint8_t* streamed_text_data_table::get_text_entry(uint16_t index)
|
||||
{
|
||||
const uint16_t num_text_entries = get_number_of_text_entries();
|
||||
const uint16_t entries_start_offset = get_entries_start_offset_of(num_text_entries);
|
||||
const uint16_t entry_offset = get_entry_offset_by_index(index_buffer_, index);
|
||||
const uint16_t entry_byte_offset = entries_start_offset + entry_offset;
|
||||
const uint16_t entry_byte_offset = get_entries_start_offset_of(num_text_entries) + get_entry_offset_by_index(index_buffer_, index);
|
||||
const uint16_t entry_size_in_bytes = get_text_entry_size(index);
|
||||
const uint16_t space_remaining_outside_lookback_window = decompression_buffer_size_ - ZX0_DEFAULT_WINDOW_SIZE;
|
||||
const uint16_t current_window_size = get_current_zx0_window_size();
|
||||
const uint16_t window_start_offset = bytes_decompressed_ - current_window_size;
|
||||
const uint16_t window_start_offset = bytes_decompressed_ - get_current_zx0_window_size();
|
||||
uint16_t bytes_to_decompress;
|
||||
uint16_t chunk_size;
|
||||
uint16_t entry_size_in_bytes;
|
||||
uint16_t entry_end_byte_offset;
|
||||
|
||||
// figure out how many bytes we need to read to have the entire text entry
|
||||
// unfortunately ZX0 doesn't have random access, so we need to linearly decompress
|
||||
// until we have reached the bytes we actually want.
|
||||
if(index != num_text_entries - 1)
|
||||
{
|
||||
const uint16_t next_entry_offset = get_entry_offset_by_index(index_buffer_, index + 1);
|
||||
entry_size_in_bytes = next_entry_offset - entry_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't have a next entry. So we need to consider the end of the file
|
||||
const uint16_t decompressed_size = static_cast<uint16_t>(zx0_decompressor_get_decompressed_size());
|
||||
entry_size_in_bytes = decompressed_size - entry_byte_offset;
|
||||
}
|
||||
entry_end_byte_offset = entry_byte_offset + entry_size_in_bytes;
|
||||
|
||||
if(entry_end_byte_offset < bytes_decompressed_)
|
||||
@@ -133,6 +150,11 @@ const uint8_t* streamed_text_data_table::get_text_entry(uint8_t index)
|
||||
return decompression_buffer_ + ZX0_DEFAULT_WINDOW_SIZE + last_chunk_size_ - entry_size_in_bytes;
|
||||
}
|
||||
|
||||
uint16_t streamed_text_data_table::get_text_entry_size(uint16_t index) const
|
||||
{
|
||||
return get_entry_size_in_bytes(index_buffer_, index);
|
||||
}
|
||||
|
||||
uint8_t* streamed_text_data_table::get_window_start() const
|
||||
{
|
||||
uint16_t without_last_chunk_size = (bytes_decompressed_ - last_chunk_size_);
|
||||
|
||||
@@ -22,6 +22,29 @@ uint line_char_index;
|
||||
const byte *curr_text;
|
||||
bool text_exit;
|
||||
|
||||
// This function was separated from text_loop to reduce the scope of the text_decompression_buffer.
|
||||
// if we didn't do this, the decompression_buffer would be kept on the stack (=IWRAM) for the entire duration of the
|
||||
// text_loop() call. This is particularly bad because the whole mystery_gift_builder sequence is being triggered from within
|
||||
// text_loop(). And there we need all the IWRAM we can muster.
|
||||
// Doing it this way does mean that we need to completely restart decompression whenever we switch from dialog entry.
|
||||
// but given that it requires user input to do so, I believe it's worth it and not time-critical.
|
||||
// attribute noinline was used to make sure the compiler doesn't inline this code back into text_loop()
|
||||
static __attribute__((noinline)) const u8* read_dialogue_text_entry(uint8_t index, u8 *output_buffer)
|
||||
{
|
||||
u8 text_decompression_buffer[3072];
|
||||
u8 index_buffer[100];
|
||||
const u8 *text_entry;
|
||||
|
||||
streamed_text_data_table dialogue_table(text_decompression_buffer, sizeof(text_decompression_buffer), index_buffer);
|
||||
|
||||
dialogue_table.decompress(get_compressed_PTGB_table());
|
||||
|
||||
text_entry = dialogue_table.get_text_entry(index);
|
||||
memcpy(output_buffer, text_entry, dialogue_table.get_text_entry_size(index));
|
||||
|
||||
return output_buffer;
|
||||
}
|
||||
|
||||
void init_text_engine()
|
||||
{
|
||||
// Load the TTE
|
||||
@@ -56,11 +79,9 @@ void init_text_engine()
|
||||
|
||||
int text_loop(int script)
|
||||
{
|
||||
u8 text_decompression_buffer[3072];
|
||||
u8 index_buffer[100];
|
||||
streamed_text_data_table dialogue_table(text_decompression_buffer, sizeof(text_decompression_buffer), index_buffer);
|
||||
|
||||
dialogue_table.decompress(get_compressed_PTGB_table());
|
||||
// we have restricted the dialog entries to 1024 bytes in the text_helper main.py
|
||||
// so we shouldn't run into problems when we only use 1 KB to contain a text entry.
|
||||
u8 diag_entry_text_buffer[1024];
|
||||
switch (script)
|
||||
{
|
||||
case BTN_TRANSFER:
|
||||
@@ -72,7 +93,7 @@ int text_loop(int script)
|
||||
break;
|
||||
}
|
||||
|
||||
curr_text = (curr_line.has_text()) ? dialogue_table.get_text_entry(curr_line.get_text_entry_index()) : NULL;
|
||||
curr_text = (curr_line.has_text()) ? read_dialogue_text_entry(curr_line.get_text_entry_index(), diag_entry_text_buffer) : NULL;
|
||||
|
||||
REG_BG1CNT = (REG_BG1CNT && !BG_PRIO_MASK) | BG_PRIO(2); // Show Fennel
|
||||
show_text_box();
|
||||
@@ -99,7 +120,7 @@ int text_loop(int script)
|
||||
break;
|
||||
}
|
||||
|
||||
curr_text = (curr_line.has_text()) ? dialogue_table.get_text_entry(curr_line.get_text_entry_index()) : NULL;
|
||||
curr_text = (curr_line.has_text()) ? read_dialogue_text_entry(curr_line.get_text_entry_index(), diag_entry_text_buffer) : NULL;
|
||||
char_index = 0;
|
||||
|
||||
if (text_exit)
|
||||
|
||||
@@ -7,6 +7,7 @@ import requests
|
||||
from collections import defaultdict
|
||||
import copy
|
||||
import math
|
||||
import sys
|
||||
|
||||
update = True
|
||||
|
||||
@@ -389,6 +390,11 @@ def write_text_bin_file(filename, dictionary):
|
||||
linedata = bytes.fromhex(dictionary[key]['bytes'])
|
||||
bindata.extend(linedata)
|
||||
current_offset += len(linedata)
|
||||
|
||||
if len(linedata) > 1024:
|
||||
print(f"Error: entry '{key}' numBytes exceeds 1024 (got {len(linedata)})", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
num += 1
|
||||
|
||||
# Write the index and bindata to the file
|
||||
|
||||
Reference in New Issue
Block a user