Skip to content

Commit

Permalink
FF8: Better tonberry compatibility (#591)
Browse files Browse the repository at this point in the history
  • Loading branch information
myst6re committed Sep 8, 2023
1 parent e0173f7 commit 033a1b1
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 23 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
## FF8

- Graphics: Fix crash when using external texture replacement ( https://github.com/julianxhokaxhiu/FFNx/pull/588 )
- Graphics: Fix texture glitches using external texture replacement ( https://github.com/julianxhokaxhiu/FFNx/pull/591 )

# 1.16.0

Expand Down
3 changes: 3 additions & 0 deletions src/ff8.h
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,9 @@ struct ff8_externals
char* disk_data_path;
uint32_t swirl_main_loop;
uint32_t field_main_loop;
uint32_t field_main_exit;
uint32_t psxvram_texture_pages_free;
uint32_t sub_4672C0;
uint32_t sub_471F70;
uint32_t sub_4767B0;
uint32_t sub_4789A0;
Expand Down
49 changes: 40 additions & 9 deletions src/ff8/texture_packer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,14 @@ void TexturePacker::setTexture(const char *name, int xBpp2, int y, int wBpp2, in
}
}

bool TexturePacker::setTextureBackground(const char *name, int x, int y, int w, int h, const std::vector<Tile> &mapTiles, int bgTexId)
bool TexturePacker::setTextureBackground(const char *name, int x, int y, int w, int h, const std::vector<Tile> &mapTiles, int bgTexId, const char *extension, char *found_extension)
{
if (trace_all || trace_vram) ffnx_trace("TexturePacker::%s %s x=%d y=%d w=%d h=%d tileCount=%d bgTexId=%d\n", __func__, name, x, y, w, h, mapTiles.size(), bgTexId);

TextureBackground tex(name, x, y, w, h, mapTiles, bgTexId);
ModdedTextureId textureId = INVALID_TEXTURE;

if (tex.createImage())
if (tex.createImage(extension, found_extension))
{
textureId = makeTextureId(x, y, TextureCategoryBackground);
}
Expand Down Expand Up @@ -198,6 +198,27 @@ bool TexturePacker::setTextureRedirection(const TextureInfos &oldTexture, const
return false;
}

void TexturePacker::clearTextures()
{
if (trace_all || trace_vram) ffnx_trace("TexturePacker::%s\n", __func__);

_tiledTexs.clear();
std::fill_n(_vramTextureIds.begin(), _vramTextureIds.size(), INVALID_TEXTURE);

for (auto &texture: _externalTextures) {
texture.second.destroyImage();
}
for (auto &texture: _textureRedirections) {
texture.second.destroyImage();
}
for (auto &texture: _backgroundTextures) {
texture.second.destroyImage();
}
_externalTextures.clear();
_textureRedirections.clear();
_backgroundTextures.clear();
}

uint8_t TexturePacker::getMaxScale(const uint8_t *texData) const
{
if (trace_all || trace_vram) ffnx_trace("TexturePacker::%s\n", __func__);
Expand Down Expand Up @@ -500,7 +521,7 @@ TexturePacker::TiledTex TexturePacker::getTiledTex(const uint8_t *texData) const
return TiledTex();
}

void TexturePacker::debugSaveTexture(int textureId, const uint32_t *source, int w, int h, bool removeAlpha, bool after)
void TexturePacker::debugSaveTexture(int textureId, const uint32_t *source, int w, int h, bool removeAlpha, bool after, TextureTypes textureType)
{
uint32_t *target = new uint32_t[w * h];

Expand All @@ -510,7 +531,7 @@ void TexturePacker::debugSaveTexture(int textureId, const uint32_t *source, int
}

char filename[MAX_PATH];
snprintf(filename, sizeof(filename), "texture-%d-%s", textureId, after ? "z-after" : "a-before");
snprintf(filename, sizeof(filename), "texture-%d-%s-type-%s", textureId, after ? "z-after" : "a-before", textureType == TextureTypes::ExternalTexture ? "external" : (textureType == TextureTypes::InternalTexture ? "internal" : "nomatch"));

if (trace_all || trace_vram) ffnx_trace("%s %s\n", __func__, filename);

Expand Down Expand Up @@ -558,7 +579,7 @@ TexturePacker::TextureInfos::TextureInfos(
{
}

bimg::ImageContainer *TexturePacker::TextureInfos::createImageContainer(const char *name, uint8_t palette_index, bool hasPal)
bimg::ImageContainer *TexturePacker::TextureInfos::createImageContainer(const char *name, uint8_t palette_index, bool hasPal, const char *extension, char *found_extension)
{
char filename[MAX_PATH] = {}, langPath[16] = {};

Expand All @@ -573,6 +594,12 @@ bimg::ImageContainer *TexturePacker::TextureInfos::createImageContainer(const ch
{
for (size_t idx = 0; idx < mod_ext.size(); idx++)
{
// Force extension
if (extension && stricmp(extension, mod_ext[idx].c_str()) != 0)
{
continue;
}

if (hasPal) {
_snprintf(filename, sizeof(filename), "%s/%s/%s%s_%02i.%s", basedir, mod_path.c_str(), langPath, name, palette_index, mod_ext[idx].c_str());
} else {
Expand All @@ -587,6 +614,10 @@ bimg::ImageContainer *TexturePacker::TextureInfos::createImageContainer(const ch
{
if (trace_all || trace_loaders || trace_vram) ffnx_trace("Using texture: %s\n", filename);

if (found_extension != nullptr) {
strncpy(found_extension, mod_ext[idx].c_str(), mod_ext[idx].size());
}

return image;
}
else if (trace_all || trace_loaders || trace_vram)
Expand Down Expand Up @@ -667,9 +698,9 @@ TexturePacker::Texture::Texture(
{
}

bool TexturePacker::Texture::createImage(uint8_t palette_index, bool has_pal)
bool TexturePacker::Texture::createImage(uint8_t palette_index, bool has_pal, const char *extension, char *found_extension)
{
_image = createImageContainer(_name.c_str(), palette_index, has_pal);
_image = createImageContainer(_name.c_str(), palette_index, has_pal, extension, found_extension);

if (_image == nullptr)
{
Expand Down Expand Up @@ -727,13 +758,13 @@ TexturePacker::TextureBackground::TextureBackground(
{
}

bool TexturePacker::TextureBackground::createImage()
bool TexturePacker::TextureBackground::createImage(const char *extension, char *foundExtension)
{
size_t size = _mapTiles.size();

_colsCount = size / (TEXTURE_HEIGHT / TILE_SIZE) + int(size % (TEXTURE_HEIGHT / TILE_SIZE) != 0);

if (! Texture::createImage(0, false)) {
if (! Texture::createImage(0, false, extension, foundExtension)) {
return false;
}

Expand Down
11 changes: 6 additions & 5 deletions src/ff8/texture_packer.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class TexturePacker {
return _bpp;
}
protected:
static bimg::ImageContainer *createImageContainer(const char *name, uint8_t palette_index, bool hasPal);
static bimg::ImageContainer *createImageContainer(const char *name, uint8_t palette_index, bool hasPal, const char *extension = nullptr, char *foundExtension = nullptr);
static uint8_t computeScale(int sourcePixelW, int sourceH, int targetPixelW, int targetH);
static void copyRect(
const uint32_t *sourceRGBA, int sourceXBpp2, int sourceYBpp2, int sourceW, uint8_t sourceScale, Tim::Bpp sourceDepth,
Expand Down Expand Up @@ -104,9 +104,10 @@ class TexturePacker {
}
void uploadTexture(const uint8_t *texture, int x, int y, int w, int h);
void setTexture(const char *name, int x, int y, int w, int h, Tim::Bpp bpp, bool isPal);
bool setTextureBackground(const char *name, int x, int y, int w, int h, const std::vector<Tile> &mapTiles, int bgTexId = -1);
bool setTextureBackground(const char *name, int x, int y, int w, int h, const std::vector<Tile> &mapTiles, int bgTexId = -1, const char *extension = nullptr, char *found_extension = nullptr);
// Override a part of the VRAM from another part of the VRAM, typically with biggest textures (Worldmap)
bool setTextureRedirection(const TextureInfos &oldTexture, const TextureInfos &newTexture, uint32_t *imageData);
void clearTextures();
uint8_t getMaxScale(const uint8_t *texData) const;
void getTextureNames(const uint8_t *texData, std::list<std::string> &names) const;
void registerTiledTex(const uint8_t *texData, int x, int y, Tim::Bpp bpp, int palX = 0, int palY = 0);
Expand All @@ -119,7 +120,7 @@ class TexturePacker {
TextureTypes drawTextures(const uint8_t *texData, struct texture_format *tex_format, uint32_t *target, const uint32_t *originalImageData, int originalW, int originalH, uint8_t scale, uint32_t paletteIndex);

bool saveVram(const char *fileName, Tim::Bpp bpp) const;
static void debugSaveTexture(int textureId, const uint32_t *source, int w, int h, bool removeAlpha, bool after);
static void debugSaveTexture(int textureId, const uint32_t *source, int w, int h, bool removeAlpha, bool after, TextureTypes textureType);
private:
enum TextureCategory {
TextureCategoryStandard,
Expand Down Expand Up @@ -152,7 +153,7 @@ class TexturePacker {
inline uint8_t scale() const {
return _scale;
}
bool createImage(uint8_t palette_index = 0, bool has_pal = true);
bool createImage(uint8_t palette_index = 0, bool has_pal = true, const char *extension = nullptr, char *foundExtension = nullptr);
void destroyImage();
inline bool hasImage() const {
return _image != nullptr;
Expand Down Expand Up @@ -180,7 +181,7 @@ class TexturePacker {
const std::vector<Tile> &mapTiles,
int textureId
);
bool createImage();
bool createImage(const char *extension = nullptr, char *foundExtension = nullptr);
void copyRect(int sourceXBpp2, int sourceYBpp2, Tim::Bpp textureBpp, uint32_t *target, int targetX, int targetY, int targetW, uint8_t targetScale) const;
private:
virtual uint8_t computeScale() const override;
Expand Down
60 changes: 56 additions & 4 deletions src/ff8/vram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
#include "../patch.h"
#include "../macro.h"
#include "../image/tim.h"
#include "../utils.h"
#include "field/background.h"
#include "field/chara_one.h"
#include "battle/stage.h"
#include "file.h"

#include <unordered_map>
#include <vector>
#include <filesystem>

TexturePacker texturePacker;

Expand Down Expand Up @@ -516,9 +518,11 @@ uint32_t ff8_field_read_map_data(char *filename, uint8_t *map_data)

std::vector<Tile> tiles = ff8_background_parse_tiles(map_data);

char tex_directory[MAX_PATH] = {};
char tex_filename[MAX_PATH] = {};

snprintf(tex_filename, MAX_PATH, "field/mapdata/%s/%s", get_current_field_name(), get_current_field_name());
snprintf(tex_directory, sizeof(tex_directory), "field/mapdata/%s", get_current_field_name());
snprintf(tex_filename, sizeof(tex_filename), "%s/%s", tex_directory, get_current_field_name());

if (save_textures_legacy) {
ff8_background_save_textures_legacy(tiles, mim_texture_buffer, tex_filename);
Expand All @@ -530,13 +534,51 @@ uint32_t ff8_field_read_map_data(char *filename, uint8_t *map_data)
return ret;
}

if (!texturePacker.setTextureBackground(tex_filename, 0, 256, VRAM_PAGE_MIM_MAX_COUNT * TEXTURE_WIDTH_BPP16, TEXTURE_HEIGHT, tiles)) {
char tex_abs_directory[MAX_PATH] = {};
snprintf(tex_abs_directory, sizeof(tex_abs_directory), "%s/%s", mod_path.c_str(), tex_directory);
bool has_dir = dirExists(tex_abs_directory);

if (!has_dir && (trace_all || trace_loaders || trace_vram)) {
ffnx_warning("Directory does not exist, fallback to Tonberry compatibility layer: %s\n", tex_abs_directory);
}

if (!has_dir || !texturePacker.setTextureBackground(tex_filename, 0, 256, VRAM_PAGE_MIM_MAX_COUNT * TEXTURE_WIDTH_BPP16, TEXTURE_HEIGHT, tiles)) {
snprintf(tex_directory, MAX_PATH, "field/mapdata/%.2s/%s", get_current_field_name(), get_current_field_name());
snprintf(tex_abs_directory, sizeof(tex_abs_directory), "%s/%s", mod_path.c_str(), tex_directory);

if (!dirExists(tex_abs_directory)) {
if (trace_all || trace_loaders || trace_vram) {
ffnx_warning("Directory does not exist, abort looking for field textures: %s\n", tex_abs_directory);
}

return ret;
}

char found_extension[MAX_PATH] = {};
char *extension = nullptr;
bool found_pages[VRAM_PAGE_MIM_MAX_COUNT] = {};

snprintf(tex_directory, MAX_PATH, "%s/%s", tex_directory, get_current_field_name());

// Compatibility with Tonberry, vram pages 13-25
for (int i = 0; i < VRAM_PAGE_MIM_MAX_COUNT; ++i) {
snprintf(tex_filename, MAX_PATH, "field/mapdata/%.2s/%s/%s_%d", get_current_field_name(), get_current_field_name(), get_current_field_name(), i);
snprintf(tex_filename, MAX_PATH, "%s_%d", tex_directory, i + VRAM_PAGE_MIM_MAX_COUNT);

if (!texturePacker.setTextureBackground(tex_filename, i * TEXTURE_WIDTH_BPP16, 256, TEXTURE_WIDTH_BPP16, TEXTURE_HEIGHT, tiles, i)) {
if (texturePacker.setTextureBackground(tex_filename, i * TEXTURE_WIDTH_BPP16, 256, TEXTURE_WIDTH_BPP16, TEXTURE_HEIGHT, tiles, i, extension, found_extension)) {
extension = found_extension;
found_pages[i] = true;
}
}

// Compatibility with Tonberry, vram pages 0-12
for (int i = 0; i < VRAM_PAGE_MIM_MAX_COUNT; ++i) {
snprintf(tex_filename, MAX_PATH, "%s_%d", tex_directory, i);

if (!found_pages[i] && !texturePacker.setTextureBackground(tex_filename, i * TEXTURE_WIDTH_BPP16, 256, TEXTURE_WIDTH_BPP16, TEXTURE_HEIGHT, tiles, i, extension, found_extension)) {
break;
}

extension = found_extension;
}
}

Expand Down Expand Up @@ -708,6 +750,13 @@ void ff8_battle_upload_texture_palette(int16_t *pos_and_size, uint8_t *texture_b
}
}

void clean_psxvram_pages()
{
texturePacker.clearTextures();

((void(*)())ff8_externals.sub_4672C0)();
}

void vram_init()
{
texturePacker.setVram((uint8_t *)ff8_externals.psxvram_buffer);
Expand Down Expand Up @@ -748,6 +797,9 @@ void vram_init()
replace_call(ff8_externals.battle_open_file + 0x1A2, ff8_battle_read_file);
replace_call(ff8_externals.battle_upload_texture_to_vram + 0x45, ff8_battle_upload_texture_palette);

// Clear texture_packer on every module exits
replace_call(ff8_externals.psxvram_texture_pages_free + 0x5A, clean_psxvram_pages);

replace_function(ff8_externals.upload_psx_vram, ff8_upload_vram);

// read_vram_to_buffer_parent_calls
Expand Down
11 changes: 7 additions & 4 deletions src/ff8_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ void ff8_find_externals()
ff8_externals.sm_pc_read = (uint32_t(*)(char*, void*))get_relative_call(ff8_externals.main_loop, 0x9C + 3);
ff8_externals.cdcheck_main_loop = get_absolute_value(ff8_externals.main_loop, 0xBB + 3);
common_externals._mode = (WORD *)get_absolute_value(ff8_externals.main_loop, 0x115 + 3);
ff8_externals.field_main_exit = get_absolute_value(ff8_externals.main_loop, 0x13C + 3);
ff8_externals.field_main_loop = get_absolute_value(ff8_externals.main_loop, 0x144 + 3);
common_externals.current_field_id = (WORD*)get_absolute_value(ff8_externals.main_loop, 0x21F + 6);
ff8_externals.worldmap_enter_main = get_absolute_value(ff8_externals.main_loop, 0x2C0 + 4);
Expand All @@ -112,6 +113,7 @@ void ff8_find_externals()
ff8_externals.sm_pc_read = (uint32_t(*)(char*, void*))get_relative_call(ff8_externals.main_loop, 0x9C);
ff8_externals.cdcheck_main_loop = get_absolute_value(ff8_externals.main_loop, 0xBB);
common_externals._mode = (WORD *)get_absolute_value(ff8_externals.main_loop, 0x115);
ff8_externals.field_main_exit = get_absolute_value(ff8_externals.main_loop, 0x13C);
ff8_externals.field_main_loop = get_absolute_value(ff8_externals.main_loop, 0x144);
common_externals.current_field_id = (WORD*)get_absolute_value(ff8_externals.main_loop, 0x21F);
ff8_externals.worldmap_enter_main = get_absolute_value(ff8_externals.main_loop, 0x2C0);
Expand All @@ -123,6 +125,9 @@ void ff8_find_externals()
ff8_externals.sub_470250 = get_relative_call(ff8_externals.main_loop, 0x6E7);
}

ff8_externals.psxvram_texture_pages_free = get_relative_call(ff8_externals.field_main_exit, 0x58);
ff8_externals.sub_4672C0 = get_relative_call(ff8_externals.psxvram_texture_pages_free, 0x5A);

common_externals.debug_print2 = get_relative_call(uint32_t(ff8_externals.sm_pc_read), 0x16);
ff8_externals.moriya_filesytem_open = get_relative_call(uint32_t(ff8_externals.sm_pc_read), 0x21);
ff8_externals.moriya_filesytem_seek = get_relative_call(uint32_t(ff8_externals.sm_pc_read), 0x77);
Expand Down Expand Up @@ -424,11 +429,9 @@ void ff8_find_externals()
ff8_externals.stop_music = get_relative_call(ff8_externals.sub_46B800, 0xB);
common_externals.set_midi_volume_trans = get_relative_call(ff8_externals.opcode_musicvoltrans, 0x49); // Formally music_volume_trans
common_externals.set_midi_volume_fade = get_relative_call(ff8_externals.opcode_musicvolfade, 0x59); // Formally music_volume_fade
ff8_externals.set_midi_volume = get_relative_call(ff8_externals.stop_music, 0x22);
ff8_externals.dmusicperf_set_volume_sub_46C6F0 = (BOOL (*)(uint32_t, int32_t))get_relative_call(ff8_externals.stop_music, 0x22);
common_externals.set_midi_volume = get_relative_call(ff8_externals.sm_battle_sound, 0x173); // Formally set_music_volume
ff8_externals.dmusicperf_set_volume_sub_46C6F0 = (BOOL (*)(uint32_t, int32_t))get_relative_call(common_externals.set_midi_volume, 0x1B);
common_externals.master_midi_volume = (DWORD*)get_absolute_value((uint32_t)ff8_externals.dmusicperf_set_volume_sub_46C6F0, 0x24);

common_externals.master_midi_volume = (DWORD*)get_absolute_value(uint32_t(ff8_externals.dmusicperf_set_volume_sub_46C6F0), 0x24);
common_externals.stop_wav = get_relative_call(ff8_externals.stop_music, 0x14);
common_externals.stop_midi = get_relative_call(ff8_externals.stop_music, 0x2A);

Expand Down
2 changes: 1 addition & 1 deletion src/music.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ void music_init()
// Not implemented by the game
replace_function(ff8_externals.opcode_musicvolsync, ff8_volume_sync);
// Called by game credits
replace_function(ff8_externals.set_midi_volume, set_music_volume);
replace_function(uint32_t(ff8_externals.dmusicperf_set_volume_sub_46C6F0), set_music_volume);
// Fix intro credits volume fadeout time
replace_call(ff8_externals.load_credits_image + 0x5DF, ff8_set_music_volume_intro_credits);
replace_call(ff8_externals.load_credits_image + 0x5C2, noop_a1);
Expand Down
6 changes: 6 additions & 0 deletions src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ bool fileExists(const char *filename)
// Use stat to keep compatibility with 7th Heaven
return stat(filename, &dummy) == 0;
}

bool dirExists(const char *filename)
{
// Fastest way
return std::filesystem::is_directory(filename);
}
1 change: 1 addition & 0 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,4 @@ inline long double elapsedMicroseconds(std::chrono::time_point<std::chrono::high
}

bool fileExists(const char *filename);
bool dirExists(const char *filename);

0 comments on commit 033a1b1

Please sign in to comment.