Skip to content

Commit

Permalink
FF8: field texture replacement
Browse files Browse the repository at this point in the history
  • Loading branch information
myst6re committed Feb 19, 2023
1 parent 6dfa7ed commit f409308
Show file tree
Hide file tree
Showing 14 changed files with 1,055 additions and 193 deletions.
37 changes: 27 additions & 10 deletions src/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ bool simulate_OK_button = false;

GamepadAnalogueIntent gamepad_analogue_intent = INTENT_NONE;

uint32_t *image_data_cache = nullptr;
uint32_t image_data_size_cache = 0;

uint8_t *image_data_scaled_cache = nullptr;
uint32_t image_data_scaled_size_cache = 0;

uint32_t noop() { return 0; }
uint32_t noop_a1(uint32_t a1) { return 0; }
uint32_t noop_a2(uint32_t a1, uint32_t a2) { return 0; }
Expand Down Expand Up @@ -1506,7 +1512,16 @@ uint32_t load_external_texture(void* image_data, uint32_t dataSize, struct textu
if (scale > 1)
{
uint32_t image_data_size = originalWidth * scale * originalHeight * scale * 4;
image_data_scaled = (uint8_t*)driver_malloc(image_data_size);
// Allocate with cache
if (image_data_scaled_size_cache == 0 || image_data_size > image_data_scaled_size_cache) {
if (image_data_scaled_cache != nullptr) {
driver_free(image_data_scaled_cache);
}
image_data_scaled_cache = (uint8_t*)driver_malloc(image_data_size);
image_data_scaled_size_cache = image_data_size;
}

image_data_scaled = image_data_scaled_cache;

// convert source data
if (image_data_scaled != nullptr)
Expand Down Expand Up @@ -1535,11 +1550,6 @@ uint32_t load_external_texture(void* image_data, uint32_t dataSize, struct textu
VRASS(texture_set, ogl.external, false);
}

if (image_data_scaled != nullptr && image_data_scaled != image_data)
{
driver_free(image_data_scaled);
}

if (textureType == TexturePacker::InternalTexture)
{
gl_replace_texture(texture_set, VREF(tex_header, palette_index), texture);
Expand Down Expand Up @@ -1822,7 +1832,17 @@ struct texture_set *common_load_texture(struct texture_set *_texture_set, struct

// allocate PBO
uint32_t image_data_size = w * h * 4;
image_data = (uint32_t*)driver_malloc(image_data_size);

// Allocate with cache
if (image_data_size_cache == 0 || image_data_size > image_data_size_cache) {
if (image_data_cache != nullptr) {
driver_free(image_data_cache);
}
image_data_cache = (uint32_t*)driver_malloc(image_data_size);
image_data_size_cache = image_data_size;
}

image_data = image_data_cache;

// convert source data
if (image_data != NULL) convert_image_data(VREF(tex_header, image_data), image_data, w, h, tex_format, invert_alpha, color_key, palette_offset, reference_alpha);
Expand All @@ -1839,9 +1859,6 @@ struct texture_set *common_load_texture(struct texture_set *_texture_set, struct
// commit PBO and populate texture set
gl_upload_texture(_texture_set, VREF(tex_header, palette_index), image_data, RendererTextureType::BGRA);
}

// free the memory buffer
driver_free(image_data);
}
}
else ffnx_unexpected("no texture format specified or no source data\n");
Expand Down
66 changes: 66 additions & 0 deletions src/ff8.h
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,66 @@ struct ff8_gfx_driver
gfx_field_EC *field_EC;
};

struct ff8_field_state_common {
uint8_t stack_data[0x140];
uint32_t field_140;
uint32_t field_144;
uint32_t field_148;
uint32_t field_14c;
uint32_t field_150;
uint32_t field_154;
uint32_t field_158;
uint32_t field_15c;
uint32_t execution_flags; // bgdraw: 0x10, bganime/rbganime: 0x980 (0x800: animation ongoing)
uint32_t field_164;
uint32_t field_168;
uint32_t field_16c;
uint32_t field_170;
uint8_t field_174; // has anim?
uint8_t field_175; // has anim mask?
uint16_t current_instruction_position; // field_176
uint32_t field_178;
uint32_t field_17c;
uint32_t field_180;
uint8_t stack_current_position; // field_184
uint8_t field_185;
uint8_t field_186;
uint8_t field_187;
};

struct ff8_field_state_background {
ff8_field_state_common common;
uint16_t bgstate; // field_188, set to -1 if off
uint16_t field_18a;
uint16_t bgparam_anim_start; // field_18c
uint16_t bgparam_anim_end; // field_18e
uint16_t bgparam_anim_speed1; // field_190
uint16_t bgparam_anim_speed2; // field_192
uint16_t bgparam_anim_flags; // field_194
uint16_t field_196;
uint32_t field_198;
uint16_t bgshadeloop_remember_stack_pointer; // field_19c
uint16_t bgshade_add_value; // field_19e
uint16_t field_1a0; // bgshadeloop
uint16_t field_1a2; // bgshadeloop
uint8_t field_1a4; // bgshadeloop
uint8_t field_1a5; // bgshadeloop
uint8_t field_1a6; // bgshadeloop
uint8_t bgshade_color1r; // field_1a7
uint8_t bgshade_color1g; // field_1a8
uint8_t bgshade_color1b; // field_1a9
uint8_t bgshade_color2r; // field_1aa
uint8_t bgshade_color2g; // field_1ab
uint8_t bgshade_color2b; // field_1ac
uint8_t bgshade_color1r_2; // field_1ad
uint8_t bgshade_color1g_2; // field_1ae
uint8_t bgshade_color1b_2; // field_1af
uint8_t bgshade_color2r_2; // field_1b0
uint8_t bgshade_color2g_2; // field_1b1
uint8_t bgshade_color2b_2; // field_1b2
uint8_t field_1b3;
};

// --------------- end of FF8 imports ---------------

// memory addresses and function pointers from FF8.exe
Expand Down Expand Up @@ -986,7 +1046,13 @@ struct ff8_externals
uint32_t read_field_data;
uint32_t upload_mim_file;
char *field_filename;
uint32_t field_scripts_init;
uint8_t *field_state_background_count;
ff8_field_state_background **field_state_backgrounds;
uint32_t load_field_models;
uint32_t chara_one_read_file;
uint32_t chara_one_seek_file;
uint32_t chara_one_upload_texture;
uint32_t worldmap_main_loop;
uint32_t worldmap_enter_main;
uint32_t worldmap_sub_53F310;
Expand Down
144 changes: 144 additions & 0 deletions src/ff8/field/background.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/****************************************************************************/
// Copyright (C) 2009 Aali132 //
// Copyright (C) 2018 quantumpencil //
// Copyright (C) 2018 Maxime Bacoux //
// Copyright (C) 2020 Chris Rizzitello //
// Copyright (C) 2020 John Pritchard //
// Copyright (C) 2023 myst6re //
// Copyright (C) 2023 Julian Xhokaxhiu //
// Copyright (C) 2023 Cosmos //
// Copyright (C) 2023 Tang-Tang Zhou //
// //
// This file is part of FFNx //
// //
// FFNx is free software: you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation, either version 3 of the License //
// //
// FFNx is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
/****************************************************************************/

#include "background.h"
#include "../../image/tim.h"
#include "../../saveload.h"
#include "../../log.h"

bool ff8_background_tiles_looks_alike(const Tile &tile, const Tile &other)
{
return tile.texID == other.texID
&& tile.palID == other.palID
&& tile.srcX == other.srcX
&& tile.srcY == other.srcY
&& tile.blendType == other.blendType;
}

std::vector<Tile> ff8_background_parse_tiles(const uint8_t *map_data)
{
std::vector<Tile> tiles;

while (true) {
Tile tile;

memcpy(&tile, map_data, sizeof(Tile));

if (tile.x == 0x7fff) {
break;
}

uint8_t texture_id = tile.texID & 0xF;
Tim::Bpp bpp = Tim::Bpp((tile.texID >> 7) & 3);
uint8_t pal_id = (tile.palID >> 6) & 0xF;

if (trace_all || trace_vram) ffnx_info("tile %d dst %d %d %d src %d %d texid %d bpp %d palId %d blendType %d param %d %d\n", tiles.size(), tile.x, tile.y, tile.z, tile.srcX, tile.srcY, texture_id, int(bpp), pal_id, tile.blendType, tile.parameter, tile.state);

tiles.push_back(tile);

map_data += sizeof(Tile);
}

return tiles;
}

bool ff8_background_save_textures(const std::vector<Tile> &tiles, const uint8_t *mim_data, const char *filename)
{
if (trace_all || trace_vram) ffnx_trace("%s %s\n", __func__, filename);

const uint16_t* const palettes_data = reinterpret_cast<const uint16_t *>(mim_data + 0x1000);
const uint8_t* const textures_data = mim_data + 0x3000;

const uint8_t cols_count = tiles.size() / (TEXTURE_HEIGHT / TILE_SIZE) + int(tiles.size() % (TEXTURE_HEIGHT / TILE_SIZE) != 0);
const uint16_t width = cols_count * TILE_SIZE;
const uint32_t image_data_size = width * TEXTURE_HEIGHT * sizeof(uint32_t);

uint32_t* const image_data_start = new uint32_t[width * TEXTURE_HEIGHT];

if (image_data_start == nullptr) {
return false;
}

// Fill with zeroes (transparent image)
memset(image_data_start, 0, image_data_size);

uint32_t tile_id = 0;

for (const Tile &tile: tiles) {
Tim::Bpp bpp = Tim::Bpp((tile.texID >> 7) & 3);
uint8_t texture_id = tile.texID & 0xF;
uint8_t pal_id = (tile.palID >> 6) & 0xF;
const uint8_t *texture_data_start = textures_data + texture_id * TEXTURE_WIDTH_BYTES + tile.srcY * MIM_DATA_WIDTH_BYTES;
const uint16_t *palette_data_start = bpp == Tim::Bpp16 ? nullptr : palettes_data + pal_id * PALETTE_SIZE;
uint8_t row = tile_id / cols_count, col = tile_id % cols_count;
uint32_t *target = image_data_start + row * TILE_SIZE * width;

if (bpp == Tim::Bpp16) {
const uint16_t *texture_data = reinterpret_cast<const uint16_t *>(texture_data_start) + tile.srcX;
target += col * TILE_SIZE;

for (int y = 0; y < TILE_SIZE; ++y) {
for (int x = 0; x < TILE_SIZE; ++x) {
*(target + x) = fromR5G5B5Color(*(texture_data + x), true);
}

target += width;
texture_data += MIM_DATA_WIDTH_BYTES / 2;
}
} else if (bpp == Tim::Bpp8) {
const uint8_t *texture_data = texture_data_start + tile.srcX;
target += col * TILE_SIZE;

for (int y = 0; y < TILE_SIZE; ++y) {
for (int x = 0; x < TILE_SIZE; ++x) {
*(target + x) = fromR5G5B5Color(palette_data_start[*(texture_data + x)], true);
}

target += width;
texture_data += MIM_DATA_WIDTH_BYTES;
}
} else {
const uint8_t *texture_data = texture_data_start + tile.srcX / 2;
target += col * TILE_SIZE;

for (int y = 0; y < TILE_SIZE; ++y) {
for (int x = 0; x < TILE_SIZE / 2; ++x) {
uint8_t index = *(texture_data + x);
*(target + x * 2) = fromR5G5B5Color(palette_data_start[index & 0xF], true);
*(target + x * 2 + 1) = fromR5G5B5Color(palette_data_start[index >> 4], true);
}

target += width;
texture_data += MIM_DATA_WIDTH_BYTES;
}
}

++tile_id;
}

save_texture(image_data_start, image_data_size, width, TEXTURE_HEIGHT, uint32_t(-1), filename, false);

delete[] image_data_start;

return true;
}
55 changes: 55 additions & 0 deletions src/ff8/field/background.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/****************************************************************************/
// Copyright (C) 2009 Aali132 //
// Copyright (C) 2018 quantumpencil //
// Copyright (C) 2018 Maxime Bacoux //
// Copyright (C) 2020 Chris Rizzitello //
// Copyright (C) 2020 John Pritchard //
// Copyright (C) 2023 myst6re //
// Copyright (C) 2023 Julian Xhokaxhiu //
// Copyright (C) 2023 Cosmos //
// Copyright (C) 2023 Tang-Tang Zhou //
// //
// This file is part of FFNx //
// //
// FFNx is free software: you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation, either version 3 of the License //
// //
// FFNx is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
/****************************************************************************/

#pragma once

#include "../../common.h"

#include <vector>

constexpr int TEXTURE_WIDTH_BYTES = 128; // Real texture width depends on the texture depth (bpp4 => 256, bpp8 => 128, bpp16 => 64)
constexpr int TEXTURE_WIDTH_BPP16 = 64;
constexpr int TEXTURE_WIDTH_BPP8 = 128;
constexpr int TEXTURE_WIDTH_BPP4 = 256;
constexpr int TEXTURE_HEIGHT = 256;
constexpr int VRAM_PAGE_MIM_MAX_COUNT = 13;
constexpr int MIM_DATA_WIDTH_BYTES = TEXTURE_WIDTH_BYTES * VRAM_PAGE_MIM_MAX_COUNT;
constexpr int MIM_DATA_HEIGHT = TEXTURE_HEIGHT;
constexpr int TILE_SIZE = 16;
constexpr int PALETTE_SIZE = 256;

struct Tile {
int16_t x, y, z;
uint16_t texID; // 2 bits = depth | 2 bits = blend | 1 bit = draw | 4 bits = textureID
uint16_t palID; // 6 bits = Always 30 | 4 bits = PaletteID | 6 bits = Always 0
uint8_t srcX, srcY;
uint8_t layerID; // 0-7
uint8_t blendType; // 0-4
uint8_t parameter, state;
};

// A tile looks like another if it uses the same texture with the same palette and uses the same blending
bool ff8_background_tiles_looks_alike(const Tile &tile, const Tile &other);

std::vector<Tile> ff8_background_parse_tiles(const uint8_t *map_data);
bool ff8_background_save_textures(const std::vector<Tile> &tiles, const uint8_t *mim_data, const char *filename);
Loading

0 comments on commit f409308

Please sign in to comment.