Skip to content

Commit

Permalink
Advanced Resolution Mode controls (#335)
Browse files Browse the repository at this point in the history
* Advanced Resolution Settings

first working version with most features implemented. rendering code happens on this side and is interacted with through CVars controlled by a UI element in SoH.

* tidying up

* Update CMakeLists.txt

* Corrected filenames and namespace

* Enforce clamp on resolution values to prevent the renderer from crashing

* Apply suggestions from code review

* Update AdvancedResolution.cpp with suggestions from code review

* Update Gui.cpp

* Consolidate AdvancedResolution into Gui

Please give me or Kenix feedback on this decision.

* Apply suggestions from code review

* Consistent capitalisation on CVars

* Grouped one more CVar with the others

CVar "gAdvancedResolutionMode" now grouped as "gAdvancedResolution.Enabled"

* Fixing a mistake in the last commit.

Missed one!
  • Loading branch information
sheepytina authored Aug 30, 2023
1 parent 0a57812 commit 3f3f29f
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 2 deletions.
88 changes: 86 additions & 2 deletions src/window/gui/Gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -384,13 +384,18 @@ void Gui::DrawMenu() {
gfx_current_game_window_viewport.width = (int16_t)size.x;
gfx_current_game_window_viewport.height = (int16_t)size.y;

if (CVarGetInteger("gAdvancedResolution.Enabled", 0)) {
ApplyResolutionChanges();
}

switch (CVarGetInteger("gLowResMode", 0)) {
case 1: { // N64 Mode
gfx_current_dimensions.width = 320;
gfx_current_dimensions.height = 240;
/*
const int sw = size.y * 320 / 240;
gfx_current_game_window_viewport.x += ((int)size.x - sw) / 2;
gfx_current_game_window_viewport.width = sw;
gfx_current_game_window_viewport.width = sw;*/
break;
}
case 2: { // 240p Widescreen
Expand Down Expand Up @@ -459,14 +464,93 @@ void Gui::ImGuiWMNewFrame() {
}
}

void Gui::ApplyResolutionChanges() {
ImVec2 size = ImGui::GetContentRegionAvail();

const float aspectRatioX = CVarGetFloat("gAdvancedResolution.AspectRatioX", 16.0f);
const float aspectRatioY = CVarGetFloat("gAdvancedResolution.AspectRatioY", 9.0f);
const uint32_t verticalPixelCount = CVarGetInteger("gAdvancedResolution.VerticalPixelCount", 480);
const bool verticalResolutionToggle = CVarGetInteger("gAdvancedResolution.VerticalResolutionToggle", 0);

const bool aspectRatioIsEnabled = (aspectRatioX > 0.0f) && (aspectRatioY > 0.0f);

const uint32_t minResolutionWidth = 320;
const uint32_t minResolutionHeight = 240;
const uint32_t maxResolutionWidth = 8096; // the renderer's actual limit is 16384
const uint32_t maxResolutionHeight = 4320; // on either axis. if you have the VRAM for it.
uint32_t newWidth = gfx_current_dimensions.width;
uint32_t newHeight = gfx_current_dimensions.height;

if (verticalResolutionToggle) { // Use fixed vertical resolution
if (aspectRatioIsEnabled) {
newWidth = uint32_t(float(verticalPixelCount / aspectRatioY) * aspectRatioX);
} else {
newWidth = uint32_t(float(verticalPixelCount * size.x / size.y));
}
newHeight = verticalPixelCount;
} else { // Use the window's resolution
if (aspectRatioIsEnabled) {
if (((float)gfx_current_game_window_viewport.width / gfx_current_game_window_viewport.height) >
(aspectRatioX / aspectRatioY)) {
// when pillarboxed
newWidth = uint32_t(float(gfx_current_dimensions.height / aspectRatioY) * aspectRatioX);
} else { // when letterboxed
newHeight = uint32_t(float(gfx_current_dimensions.width / aspectRatioX) * aspectRatioY);
}
} // else, having both options turned off does nothing.
}
// clamp values to prevent renderer crash
if (newWidth < minResolutionWidth) {
newWidth = minResolutionWidth;
}
if (newHeight < minResolutionHeight) {
newHeight = minResolutionHeight;
}
if (newWidth > maxResolutionWidth) {
newWidth = maxResolutionWidth;
}
if (newHeight > maxResolutionHeight) {
newHeight = maxResolutionHeight;
}
// apply new dimensions
gfx_current_dimensions.width = newWidth;
gfx_current_dimensions.height = newHeight;
// centring the image is done in Gui::StartFrame().
}

void Gui::StartFrame() {
const ImVec2 mainPos = ImGui::GetWindowPos();
ImVec2 size = ImGui::GetContentRegionAvail();
ImVec2 pos = ImVec2(0, 0);
if (CVarGetInteger("gLowResMode", 0) == 1) {
if (CVarGetInteger("gLowResMode", 0) == 1) { // N64 Mode takes priority
const float sw = size.y * 320.0f / 240.0f;
pos = ImVec2(size.x / 2 - sw / 2, 0);
size = ImVec2(sw, size.y);
} else if (CVarGetInteger("gAdvancedResolution.Enabled", 0)) {
if (!CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0)) {
if (!CVarGetInteger("gAdvancedResolution.IgnoreAspectCorrection", 0)) {
float sWdth = size.y * gfx_current_dimensions.width / gfx_current_dimensions.height;
float sHght = size.x * gfx_current_dimensions.height / gfx_current_dimensions.width;
float sPosX = size.x / 2 - sWdth / 2;
float sPosY = size.y / 2 - sHght / 2;
if (sPosY < 0.0f) { // pillarbox
sPosY = 0.0f; // clamp y position
sHght = size.y; // reset height
}
if (sPosX < 0.0f) { // letterbox
sPosX = 0.0f; // clamp x position
sWdth = size.x; // reset width
}
pos = ImVec2(sPosX, sPosY);
size = ImVec2(sWdth, sHght);
}
} else { // in pixel perfect mode it's much easier
const int factor = CVarGetInteger("gAdvancedResolution.IntegerScaleFactor", 1);
float sPosX = size.x / 2 - (gfx_current_dimensions.width * factor) / 2;
float sPosY = size.y / 2 - (gfx_current_dimensions.height * factor) / 2;
pos = ImVec2(sPosX, sPosY);
size = ImVec2(float(gfx_current_dimensions.width) * factor, float(gfx_current_dimensions.height) * factor);
}
}
if (gfxFramebuffer) {
ImGui::SetCursorPos(pos);
Expand Down
1 change: 1 addition & 0 deletions src/window/gui/Gui.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class Gui {
void ImGuiWMNewFrame();
void ImGuiRenderDrawData(ImDrawData* data);
ImTextureID GetTextureById(int32_t id);
void ApplyResolutionChanges();

private:
struct GuiTexture {
Expand Down

0 comments on commit 3f3f29f

Please sign in to comment.