Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FF7: Add option to remove top/bottom black bars on the screen #767

Merged
merged 1 commit into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- Music: Add the ability to play a custom `main_menu` music file on the new game screen.

## FF7

- Rendering: Add uncrop option to remove black bars from top/bottom of the screen ( https://github.com/julianxhokaxhiu/FFNx/pull/767 )

## FF8

- SFX: Fix incorrect volume assignment when playing sfx effects using the external layer
Expand Down
5 changes: 5 additions & 0 deletions misc/FFNx.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ internal_resolution_scale = 0
#~~~~~~~~~~~~~~~~~~~~~~~~~~~
aspect_ratio = 0

#[UNCROP]
# Uncrops the image to remove the black bars on the top and bottom of the screen.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~
enable_uncrop = false

#[ENABLE VSYNC]
#~~~~~~~~~~~~~~~~~~~~~~~~~~~
enable_vsync = true
Expand Down
2 changes: 2 additions & 0 deletions src/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ long window_size_x;
long window_size_y;
long internal_resolution_scale;
long aspect_ratio;
bool enable_uncrop;
bool fullscreen;
bool borderless;
long refresh_rate;
Expand Down Expand Up @@ -249,6 +250,7 @@ void read_cfg()
window_size_y = config["window_size_y"].value_or(0);
internal_resolution_scale = config["internal_resolution_scale"].value_or(0);
aspect_ratio = config["aspect_ratio"].value_or(0);
enable_uncrop = config["enable_uncrop"].value_or(false);
fullscreen = config["fullscreen"].value_or(false);
borderless = config["borderless"].value_or(false);
refresh_rate = config["refresh_rate"].value_or(0);
Expand Down
1 change: 1 addition & 0 deletions src/cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ extern long window_size_x;
extern long window_size_y;
extern long internal_resolution_scale;
extern long aspect_ratio;
extern bool enable_uncrop;
extern bool fullscreen;
extern bool borderless;
extern long refresh_rate;
Expand Down
62 changes: 46 additions & 16 deletions src/ff7/field/background.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@ namespace ff7::field
{
const int left_offset = 352 + (is_fieldmap_wide() ? abs(wide_viewport_x) : 0);
const int right_offset = is_fieldmap_wide() ? abs(wide_viewport_x) : 0;
const int top_offset = 256 + (widescreen_enabled ? 8 : 0);
const int bottom_offset = widescreen_enabled ? 8 : 0;
const int top_offset = 256 + (enable_uncrop ? 8 : 0);
const int bottom_offset = enable_uncrop ? 8 : 0;
const int half_width = is_fieldmap_wide() ? ceil(wide_viewport_width / 4) : 160;
const int half_height = widescreen_enabled ? 120 : 112;
const int half_height = enable_uncrop ? 120 : 112;

if(tile_position->x <= bg_position->x - left_offset || tile_position->x >= bg_position->x + right_offset)
tile_position->x += (tile_position->x >= bg_position->x - half_width) ? -layer3_width : layer3_width;
Expand Down Expand Up @@ -167,14 +167,14 @@ namespace ff7::field
else
z_value = 0.9998;

const bool do_increase_height = widescreen_enabled;
const bool do_increase_height = enable_uncrop;
const bool do_increase_width = is_fieldmap_wide() && (*ff7_externals.field_triggers_header)->bg3_width < ceil(wide_viewport_width / 2);
const int layer3_width = (*ff7_externals.field_triggers_header)->bg3_width * (do_increase_width ? 2 : 1);
const int layer3_height = (*ff7_externals.field_triggers_header)->bg3_height * (do_increase_height ? 2 : 1);
const int left_offset = 352 + (is_fieldmap_wide() ? abs(wide_viewport_x) : 0);
const int right_offset = is_fieldmap_wide() ? abs(wide_viewport_x) : 0;
const int top_offset = 256 + (widescreen_enabled ? 8 : 0);
const int bottom_offset = widescreen_enabled ? 8 : 0;
const int top_offset = 256 + (enable_uncrop ? 8 : 0);
const int bottom_offset = enable_uncrop ? 8 : 0;

for(int i = 0; i < *ff7_externals.field_layer3_tiles_num; i++)
{
Expand Down Expand Up @@ -202,7 +202,7 @@ namespace ff7::field
layer3_tiles[tile_index].v, layer3_tiles[tile_index].palette_index, page);
}

if(widescreen_enabled)
if(widescreen_enabled || enable_uncrop)
{
// Apply repeat x-y for background layer 4 tiles
std::vector<vector2<int>> tile_offsets;
Expand Down Expand Up @@ -250,8 +250,8 @@ namespace ff7::field
{
const int left_offset = 352 + (is_fieldmap_wide() ? abs(wide_viewport_x) : 0);
const int right_offset = is_fieldmap_wide() ? abs(wide_viewport_x) : 0;
const int top_offset = 256 + (widescreen_enabled ? 8 : 0);
const int bottom_offset = widescreen_enabled ? 8 : 0;
const int top_offset = 256 + (enable_uncrop ? 8 : 0);
const int bottom_offset = enable_uncrop ? 8 : 0;
const int half_width = is_fieldmap_wide() ? ceil(wide_viewport_width / 4) : 160;

if(tile_position->x <= bg_position->x - left_offset || tile_position->x >= bg_position->x + right_offset)
Expand Down Expand Up @@ -289,14 +289,14 @@ namespace ff7::field
initial_pos.y = ((ff7_field_center ? 232 : 224) - bg_position.y) * field_bg_multiplier;
float z_value = ff7_externals.field_layer_sub_623C0F(ff7_externals.field_camera_rotation_matrix_CFF3D8, ff7_externals.modules_global_object->field_AE, 0, 0);

const bool do_increase_height = widescreen_enabled;
const bool do_increase_height = enable_uncrop;
const bool do_increase_width = is_fieldmap_wide() && (*ff7_externals.field_triggers_header)->bg4_width < ceil(wide_viewport_width / 2);
const int layer4_width = (*ff7_externals.field_triggers_header)->bg4_width * (do_increase_width ? 2 : 1);
const int layer4_height = (*ff7_externals.field_triggers_header)->bg4_height * (do_increase_height ? 2 : 1);
const int left_offset = 352 + (is_fieldmap_wide() ? abs(wide_viewport_x) : 0);
const int right_offset = is_fieldmap_wide() ? abs(wide_viewport_x) : 0;
const int top_offset = 256 + (widescreen_enabled ? 8 : 0);
const int bottom_offset = widescreen_enabled ? 8 : 0;
const int top_offset = 256 + (enable_uncrop ? 8 : 0);
const int bottom_offset = enable_uncrop ? 8 : 0;

for(int i = 0; i < *ff7_externals.field_layer4_tiles_num; i++)
{
Expand Down Expand Up @@ -326,7 +326,7 @@ namespace ff7::field
}
}

if(widescreen_enabled)
if(widescreen_enabled || enable_uncrop)
{
// Apply repeat x-y for background layer 4 tiles
std::vector<vector2<int>> tile_offsets;
Expand Down Expand Up @@ -420,10 +420,13 @@ namespace ff7::field
float half_width = 160;
auto camera_range = field_triggers_header_ptr->camera_range;

if(widescreen_enabled && is_fieldmap_wide())
if(widescreen_enabled || enable_uncrop)
{
camera_range = widescreen.getCameraRange();
}

if(is_fieldmap_wide())
{
// Adjustment to prevent scrolling stopping one pixel too early
camera_range.left += 1;
camera_range.right -= 1;
Expand Down Expand Up @@ -480,10 +483,13 @@ namespace ff7::field
float half_width = 160;
auto camera_range = trigger_header->camera_range;

if(widescreen_enabled && is_fieldmap_wide())
if (enable_uncrop || widescreen_enabled)
{
camera_range = widescreen.getCameraRange();
}

if(is_fieldmap_wide())
{
// This centers the background if necessary
int cameraRangeSize = camera_range.right - camera_range.left;
half_width = 160 + std::min(53, cameraRangeSize / 2 - 160);
Expand Down Expand Up @@ -543,12 +549,23 @@ namespace ff7::field
float half_width = 160 + std::min(53, cameraRangeSize / 2 - 160);

point->x += widescreen.getHorizontalOffset();
point->y += widescreen.getVerticalOffset();

if (point->x > camera_range.right - half_width)
point->x = camera_range.right - half_width;
if (point->x < camera_range.left + half_width)
point->x = camera_range.left + half_width;
}

void field_uncropped_height_clip_with_camera_range(vector2<short>* point)
{
if(!widescreen.isScriptedClipEnabled())
{
return;
}

auto camera_range = widescreen.getCameraRange();

point->y += widescreen.getVerticalOffset();

if(widescreen.isScriptedVerticalClipEnabled())
{
Expand Down Expand Up @@ -642,6 +659,9 @@ namespace ff7::field

if(is_fieldmap_wide())
field_widescreen_width_clip_with_camera_range(&world_pos);
if(is_fieldmap_uncropped())
field_uncropped_height_clip_with_camera_range(&world_pos);


*ff7_externals.scripted_world_initial_pos_x = -world_pos.x;
*ff7_externals.scripted_world_initial_pos_y = -world_pos.y;
Expand All @@ -653,6 +673,8 @@ namespace ff7::field
world_pos = {-(ff7_externals.modules_global_object->field_A), -(ff7_externals.modules_global_object->field_C)};
if(is_fieldmap_wide())
field_widescreen_width_clip_with_camera_range(&world_pos);
if(is_fieldmap_uncropped())
field_uncropped_height_clip_with_camera_range(&world_pos);

*ff7_externals.field_curr_delta_world_pos_x = -world_pos.x;
*ff7_externals.field_curr_delta_world_pos_y = -world_pos.y;
Expand All @@ -667,13 +689,17 @@ namespace ff7::field
world_pos = {(-*ff7_externals.field_curr_delta_world_pos_x), -(*ff7_externals.field_curr_delta_world_pos_y)};
if(is_fieldmap_wide())
field_widescreen_width_clip_with_camera_range(&world_pos);
if(is_fieldmap_uncropped())
field_uncropped_height_clip_with_camera_range(&world_pos);

*ff7_externals.scripted_world_initial_pos_x = -world_pos.x;
*ff7_externals.scripted_world_initial_pos_y = -world_pos.y;

world_pos = {-(ff7_externals.modules_global_object->field_A), -(ff7_externals.modules_global_object->field_C)};
if(is_fieldmap_wide())
field_widescreen_width_clip_with_camera_range(&world_pos);
if(is_fieldmap_uncropped())
field_uncropped_height_clip_with_camera_range(&world_pos);

*ff7_externals.scripted_world_final_pos_x = -world_pos.x;
*ff7_externals.scripted_world_final_pos_y = -world_pos.y;
Expand Down Expand Up @@ -776,6 +802,8 @@ namespace ff7::field
field_widescreen_width_clip_with_camera_range(&world_pos);
*ff7_externals.scripted_world_initial_pos_x = -world_pos.x;
}
if(is_fieldmap_uncropped())
field_uncropped_height_clip_with_camera_range(&world_pos);

std::function<int(int, int, int, int)> field_get_interpolated_value = ff7_externals.modules_global_object->world_move_mode == 5 ?
ff7_externals.field_get_linear_interpolated_value : ff7_externals.field_get_smooth_interpolated_value;
Expand Down Expand Up @@ -831,6 +859,8 @@ namespace ff7::field
field_widescreen_width_clip_with_camera_range(&world_pos);
*ff7_externals.field_curr_delta_world_pos_x = -world_pos.x;
}
if(is_fieldmap_uncropped())
field_uncropped_height_clip_with_camera_range(&world_pos);
}

if(is_position_valid(field_curr_delta_world_pos))
Expand Down
2 changes: 1 addition & 1 deletion src/ff7/field/enter.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ namespace ff7::field
external_data.blinkFrameIndex = BLINKING_FRAMES;
}

if(widescreen_enabled) widescreen.initParamsFromConfig();
if(widescreen_enabled || enable_uncrop) widescreen.initParamsFromConfig();
}
}
5 changes: 4 additions & 1 deletion src/ff7/field/field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,11 @@ namespace ff7::field
if(widescreen_enabled)
{
x -= abs(wide_viewport_x);
y -= ff7_field_center ? 16 : 0;
width += (wide_viewport_width - game_width);
}
if(enable_uncrop)
{
y -= ff7_field_center ? 16 : 0;
height += 32;
}
ff7_externals.field_sub_63AC3F(x, y, width, height);
Expand Down
5 changes: 5 additions & 0 deletions src/ff7/field/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ namespace ff7::field
return widescreen_enabled && widescreen.getMode() != WM_DISABLED;
}

inline bool is_fieldmap_uncropped()
{
return enable_uncrop && widescreen.getMode() != WM_DISABLED;
}

inline float field_get_linear_interpolated_value_float(float initial_value, float final_value, int n_steps, int step_idx)
{
return std::lerp(initial_value, final_value, step_idx / (float)n_steps);
Expand Down
4 changes: 2 additions & 2 deletions src/ff7_opengl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,9 @@ void ff7_init_hooks(struct game_obj *_game_object)
replace_call_function(ff7_externals.battle_set_do_render_menu_call, ff7::battle::battle_menu_enter);

// #####################
// widescreen
// widescreen / uncrop
// #####################
if(widescreen_enabled)
if(widescreen_enabled || enable_uncrop)
ff7_widescreen_hook_init();

if (enable_time_cycle)
Expand Down
30 changes: 16 additions & 14 deletions src/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1722,6 +1722,22 @@ void Renderer::setScissor(uint16_t x, uint16_t y, uint16_t width, uint16_t heigh
scissorWidth = getInternalCoordX(width);
scissorHeight = getInternalCoordY(height);

// This removes the black bars on the top and bottom of the screen
if (enable_uncrop)
{
bool is_movie_playing = *ff7_externals.word_CC1638 && !ff7_externals.modules_global_object->BGMOVIE_flag;
if((is_movie_playing && widescreen.getMovieMode() == WM_DISABLED))
{
return;
}

if(y == 16 && height == 448)
{
scissorOffsetY = getInternalCoordY(0.0);
scissorHeight = getInternalCoordY(480);
}
}

if(!widescreen_enabled) return;

struct game_mode* mode = getmode_cached();
Expand All @@ -1743,13 +1759,6 @@ void Renderer::setScissor(uint16_t x, uint16_t y, uint16_t width, uint16_t heigh
return;
}

// This removes the black bars on the top and bottom of the screen
if(y == 16 && height == 448)
{
scissorOffsetY = getInternalCoordY(0.0);
scissorHeight = getInternalCoordY(480);
}

// This changes the scissor width and makes it bigger to fit widescreen
if(x == 0 && width == game_width)
scissorWidth = getInternalCoordX(wide_viewport_width);
Expand All @@ -1759,13 +1768,6 @@ void Renderer::setScissor(uint16_t x, uint16_t y, uint16_t width, uint16_t heigh
break;
case MODE_SWIRL:
{
// This removes the black bars on the top and bottom of the screen
if(y == 16 && height == 448)
{
scissorOffsetY = getInternalCoordY(0.0);
scissorHeight = getInternalCoordY(480);
}

// This changes the scissor width and makes it bigger to fit widescreen
if(x == 0 && width == game_width)
scissorWidth = getInternalCoordX(wide_viewport_width);
Expand Down