commit 1de972a7
Updateed docs for SagoLogicalResize and ran astyle for the rest
Changed files
diff --git a/source/code/HelpGamepadState.cpp b/source/code/HelpGamepadState.cpp
index 480a130..4aebbd6 100644
--- a/source/code/HelpGamepadState.cpp
+++ b/source/code/HelpGamepadState.cpp
@@ -67,7 +67,7 @@ void HelpGamepadState::ProcessInput(const SDL_Event& event, bool& processed) {
#define OFFSETX (-512+globalData.xsize/2)
-static void RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) {
+static void RenderDrawLine(SDL_Renderer* renderer, int x1, int y1, int x2, int y2) {
globalData.logicalResize.LogicalToPhysical(&x1, &y1);
globalData.logicalResize.LogicalToPhysical(&x2, &y2);
SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
diff --git a/source/code/HelpHowtoState.cpp b/source/code/HelpHowtoState.cpp
index 53716c3..d39c663 100644
--- a/source/code/HelpHowtoState.cpp
+++ b/source/code/HelpHowtoState.cpp
@@ -131,7 +131,7 @@ HelpHowtoState::~HelpHowtoState() {
const double PI =3.141592653589793238463;
-static void RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) {
+static void RenderDrawLine(SDL_Renderer* renderer, int x1, int y1, int x2, int y2) {
globalData.logicalResize.LogicalToPhysical(&x1, &y1);
globalData.logicalResize.LogicalToPhysical(&x2, &y2);
SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
diff --git a/source/code/SagoImGui.cpp b/source/code/SagoImGui.cpp
index f76bf22..df3d404 100644
--- a/source/code/SagoImGui.cpp
+++ b/source/code/SagoImGui.cpp
@@ -29,7 +29,8 @@ void InitImGui(SDL_Window* window, SDL_Renderer* renderer, int width, int height
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
- ImGuiIO& io = ImGui::GetIO(); (void)io;
+ ImGuiIO& io = ImGui::GetIO();
+ (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.DisplaySize.x = static_cast<float>(width);
diff --git a/source/code/highscore.cpp b/source/code/highscore.cpp
index ff92447..1bf08e2 100644
--- a/source/code/highscore.cpp
+++ b/source/code/highscore.cpp
@@ -58,7 +58,8 @@ Highscore::Highscore(const std::string& type, double speed) : filename(type+".js
json j = json::parse(readFileContent);
try {
j.at("highscore").get_to(table);
- } catch (json::exception& e) {
+ }
+ catch (json::exception& e) {
std::cerr << "Failed to read highscore " << filename << " due to formatting errors. Resetting the file. Reason: " <<
e.what() << "\n";
table.clear();
diff --git a/source/code/main.cpp b/source/code/main.cpp
index af7e2ef..c9bea2d 100644
--- a/source/code/main.cpp
+++ b/source/code/main.cpp
@@ -1761,7 +1761,7 @@ int runGame(Gametype gametype, int level) {
bool pressed = false;
int x = 0;
int y = 0;
-
+
theGame.GetBrickCoordinateFromMouse(pressed, mousex, mousey, x, y);
if (pressed) {
a.action = BlockGameAction::Action::MOUSE_DOWN;
diff --git a/source/code/puzzlehandler.cpp b/source/code/puzzlehandler.cpp
index 1205946..fba55b9 100644
--- a/source/code/puzzlehandler.cpp
+++ b/source/code/puzzlehandler.cpp
@@ -96,7 +96,8 @@ void LoadClearData() {
json j = json::parse(readFileContent);
try {
j.at("cleared").get_to(puzzleCleared);
- } catch (json::exception& e) {
+ }
+ catch (json::exception& e) {
std::cerr << "Failed to read \"" << puzzleSavePath << "\". File will be regenerated. Reason: " << e.what() << "\n";
puzzleCleared.clear();
}
@@ -180,8 +181,7 @@ void EditorAddPuzzle(size_t level) {
if (nrOfPuzzles >= maxNrOfPuzzleStages) {
return;
}
- if (level >= maxNrOfPuzzleStages)
- {
+ if (level >= maxNrOfPuzzleStages) {
level = 0;
}
memmove( puzzleLevels[level+1], puzzleLevels[level], sizeof(puzzleLevels[0])*(maxNrOfPuzzleStages-level-1) );
diff --git a/source/code/sago/SagoLogicalResize.hpp b/source/code/sago/SagoLogicalResize.hpp
index 2d9074f..53db267 100644
--- a/source/code/sago/SagoLogicalResize.hpp
+++ b/source/code/sago/SagoLogicalResize.hpp
@@ -29,30 +29,99 @@ SOFTWARE.
namespace sago {
-class SagoLogicalResize
-{
+/**
+ * @brief Provides coordinate transformation between logical and physical screen coordinates.
+ *
+ * This class helps create resolution-independent layouts by defining coordinates in a fixed
+ * "logical" resolution and automatically converting them to the actual "physical" screen size.
+ * It maintains aspect ratio by adding letterboxing/pillarboxing margins when needed.
+ *
+ * Key concepts:
+ * - Logical coordinates: Fixed coordinate system you design for (e.g., 1920x1080)
+ * - Physical coordinates: Actual screen/window size (e.g., 1280x720, 3840x2160, etc.)
+ * - Scale factor: Calculated to fit logical size into physical size while preserving aspect ratio
+ * - Margins: Black bars added to maintain aspect ratio (letterboxing/pillarboxing)
+ * - Tile alignment: As long as tiles are resized with LogicalToPhysical, they will align correctly. No gaps or overlaps.
+ *
+ * Example usage:
+ * @code
+ * // Design your UI for 1920x1080
+ * SagoLogicalResize resize(1920, 1080);
+ * resize.SetPhysicalSize(window_width, window_height);
+ *
+ * // Draw at logical position (100, 100)
+ * int phys_x, phys_y;
+ * resize.LogicalToPhysical(100, 100, phys_x, phys_y);
+ * DrawSprite(renderer, phys_x, phys_y);
+ *
+ * // Handle mouse input
+ * int log_x, log_y;
+ * resize.PhysicalToLogical(mouse_x, mouse_y, log_x, log_y);
+ * if (log_x > 100 && log_x < 200) { ... }
+ * @endcode
+ */
+class SagoLogicalResize {
public:
- SagoLogicalResize() : logical_width_(1), logical_height_(1), physical_width_(1), physical_height_(1) { SetScaleFactor(); }
+ /**
+ * @brief Default constructor with minimal 1x1 logical size.
+ */
+ SagoLogicalResize() : logical_width_(1), logical_height_(1), physical_width_(1), physical_height_(1) {
+ SetScaleFactor();
+ }
+
+ /**
+ * @brief Constructor with specified logical resolution.
+ * @param logical_width The width of the logical coordinate system (minimum 1)
+ * @param logical_height The height of the logical coordinate system (minimum 1)
+ */
SagoLogicalResize(int logical_width, int logical_height)
- : logical_width_(std::max(1, logical_width)), logical_height_(std::max(1, logical_height)), physical_width_(1), physical_height_(1) { SetScaleFactor(); }
+ : logical_width_(std::max(1, logical_width)), logical_height_(std::max(1, logical_height)), physical_width_(1), physical_height_(1) {
+ SetScaleFactor();
+ }
- void SetPhysicalSize(int physical_width, int physical_height)
- {
+ /**
+ * @brief Updates the physical (actual) screen size and recalculates scaling.
+ *
+ * Call this when the window is resized or when initializing the physical display size.
+ * This recalculates the scale factor and margins to fit the logical size into the physical size.
+ *
+ * @param physical_width The actual width of the screen/window (minimum 1)
+ * @param physical_height The actual height of the screen/window (minimum 1)
+ */
+ void SetPhysicalSize(int physical_width, int physical_height) {
//Physical size must be at least 1. Less than 1 is not drawn anyway and it prevents division by zero.
physical_width_ = std::max(1, physical_width);
physical_height_ = std::max(1, physical_height);
SetScaleFactor();
}
- void LogicalToPhysical(int logical_x, int logical_y, int &physical_x, int &physical_y) const
- {
+ /**
+ * @brief Converts logical coordinates to physical screen coordinates.
+ *
+ * This applies the scale factor and adds the appropriate margins.
+ * Use this to convert positions where you want to draw elements on screen.
+ *
+ * @param logical_x The x coordinate in logical space
+ * @param logical_y The y coordinate in logical space
+ * @param physical_x Output: the x coordinate in physical screen space
+ * @param physical_y Output: the y coordinate in physical screen space
+ */
+ void LogicalToPhysical(int logical_x, int logical_y, int& physical_x, int& physical_y) const {
physical_x = logical_x;
physical_y = logical_y;
LogicalToPhysical(&physical_x, &physical_y);
}
- void LogicalToPhysical(int *x, int *y) const
- {
+ /**
+ * @brief Converts logical coordinates to physical screen coordinates (pointer version).
+ *
+ * This applies the scale factor and adds the appropriate margins.
+ * Null pointers are safely ignored.
+ *
+ * @param x Pointer to x coordinate (will be converted in place), can be null
+ * @param y Pointer to y coordinate (will be converted in place), can be null
+ */
+ void LogicalToPhysical(int* x, int* y) const {
if (x) {
*x = *x * scale_factor_ + left_margin_;
}
@@ -61,8 +130,19 @@ public:
}
}
- void LogicalToPhysical(SDL_Rect &inout) const
- {
+ /**
+ * @brief Converts a logical rectangle to physical screen coordinates.
+ *
+ * This converts both the position AND size of a rectangle. The rectangle
+ * is transformed in place. Use this for converting areas/regions rather than
+ * just single points.
+ *
+ * Note: This properly handles the size conversion by converting the bottom-right
+ * corner and calculating the new width/height from the difference.
+ *
+ * @param inout The rectangle in logical coordinates (input), converted to physical coordinates (output)
+ */
+ void LogicalToPhysical(SDL_Rect& inout) const {
SDL_Rect input = inout;
LogicalToPhysical(&inout.x, &inout.y);
LogicalToPhysical(input.x + input.w + 1, input.y + input.h + 1, inout.w, inout.h);
@@ -70,37 +150,70 @@ public:
inout.h -= inout.y - 1;
}
- void PhysicalToLogical(int physical_x, int physical_y, int &logical_x, int &logical_y) const
- {
+ /**
+ * @brief Converts physical screen coordinates to logical coordinates.
+ *
+ * Use this to convert mouse input or other physical positions back to your
+ * logical coordinate system for hit detection and input handling.
+ * This removes margins and applies inverse scaling.
+ *
+ * @param physical_x The x coordinate in physical screen space
+ * @param physical_y The y coordinate in physical screen space
+ * @param logical_x Output: the x coordinate in logical space
+ * @param logical_y Output: the y coordinate in logical space
+ */
+ void PhysicalToLogical(int physical_x, int physical_y, int& logical_x, int& logical_y) const {
logical_x = (physical_x - left_margin_) / scale_factor_;
logical_y = (physical_y - top_margin_) / scale_factor_;
}
- int GetTopMargin() const
- {
+ /**
+ * @brief Gets the top margin (letterboxing/pillarboxing offset).
+ *
+ * This is the black bar size at the top when the aspect ratio requires vertical margins.
+ * Useful for debugging or custom rendering that needs to know the drawable area.
+ *
+ * @return The top margin in physical pixels
+ */
+ int GetTopMargin() const {
return top_margin_;
}
- int GetLeftMargin() const
- {
+ /**
+ * @brief Gets the left margin (letterboxing/pillarboxing offset).
+ *
+ * This is the black bar size on the left when the aspect ratio requires horizontal margins.
+ * Useful for debugging or custom rendering that needs to know the drawable area.
+ *
+ * @return The left margin in physical pixels
+ */
+ int GetLeftMargin() const {
return left_margin_;
}
private:
- void SetScaleFactor()
- {
+ /**
+ * @brief Calculates the scale factor and margins based on current logical and physical sizes.
+ *
+ * The scale factor is chosen to fit the logical size into the physical size while
+ * maintaining aspect ratio. The margins center the content on screen.
+ *
+ * Scale factor = min(physical_width/logical_width, physical_height/logical_height)
+ * This ensures the content fits in both dimensions without distortion.
+ */
+ void SetScaleFactor() {
scale_factor_ = std::min(physical_width_ / logical_width_, physical_height_ / logical_height_);
left_margin_ = (physical_width_ - logical_width_ * scale_factor_) / 2;
top_margin_ = (physical_height_ - logical_height_ * scale_factor_) / 2;
}
- double scale_factor_;
- int top_margin_;
- int left_margin_;
- double logical_width_;
- double logical_height_;
- double physical_width_;
- double physical_height_;
+ double scale_factor_; ///< Multiplier to convert logical size to physical size
+ int top_margin_; ///< Vertical offset for centering (letterboxing)
+ int left_margin_; ///< Horizontal offset for centering (pillarboxing)
+ double logical_width_; ///< Width of the logical coordinate system
+ double logical_height_; ///< Height of the logical coordinate system
+ double physical_width_; ///< Actual width of the screen/window
+ double physical_height_; ///< Actual height of the screen/window
};
} // namespace sago
\ No newline at end of file
diff --git a/source/code/stageclearhandler.cpp b/source/code/stageclearhandler.cpp
index 5b6d4bd..98011a4 100644
--- a/source/code/stageclearhandler.cpp
+++ b/source/code/stageclearhandler.cpp
@@ -85,7 +85,8 @@ void LoadStageClearStages() {
json j = json::parse(readFileContent);
try {
j.at("stages").get_to(stages);
- } catch (json::exception& e) {
+ }
+ catch (json::exception& e) {
std::cerr << "Failed to read highscore " << stageClearSaveName << " due to formatting errors. Resetting the file. Reason: " <<
e.what() << "\n";
stages.clear();
@@ -98,7 +99,8 @@ void LoadStageClearStages() {
json j = json::parse(readFileContent);
try {
j.at("stages").get_to(parScores);
- } catch (json::exception& e) {
+ }
+ catch (json::exception& e) {
std::cerr << "Failed to read par times. Reason: " << e.what() << "\n";
}
stages.resize(nrOfStageLevels);
diff --git a/source/code/themes.cpp b/source/code/themes.cpp
index 64c0ff7..5a3645b 100644
--- a/source/code/themes.cpp
+++ b/source/code/themes.cpp
@@ -138,7 +138,7 @@ static size_t current_theme = 0;
void ThemesFillMissingFields(Theme& theme) {
- if (theme.background.name.empty() || !ThemesBackgroundExists(theme.background.name) ){
+ if (theme.background.name.empty() || !ThemesBackgroundExists(theme.background.name) ) {
//If the theme does not define a background then use the standard.
theme.background.name = "standard";
}