1
1
Fork
You've already forked wack
1

fix bug in calculus in texture_font.cpp #2

Open
drex_vk wants to merge 2 commits from drex_vk/wack:fix-calculus-bug into main
pull from: drex_vk/wack:fix-calculus-bug
merge into: whou:main
whou:main
First-time contributor
Copy link

Hello.

I Locate a little error calculated in texture_font.cpp so because you reversed the width and height of the tiles and i the code.

drex_vk :)

Hello. I Locate a little error calculated in texture_font.cpp so because you reversed the width and height of the tiles and i the code. drex_vk :)
Owner
Copy link

Great to see you again! Reviewing this soon, apologies for taking too long.

Great to see you again! Reviewing this soon, apologies for taking too long.
@ -56,1 +48,4 @@
const std::uint32_t columIndex = charIndex / mColumns;
const std::uint32_t rowIndex = charIndex % mColumns;
std::uint32_t x = rowIndex * (mCharWidth + mHorizontalSpacing);
Owner
Copy link

Thanks for the formula simplification, I did not catch that

Thanks for the formula simplification, I did not catch that
whou marked this conversation as resolved
@ -39,3 +39,2 @@
mRows = std::floor(texture->width / (mCharWidth + horizontalSpacing));
mColumns = std::floor(texture->height / (mCharHeight + verticalSpacing));
mRows = texture->width / (mCharWidth + horizontalSpacing);
Owner
Copy link

Only now i have realized that I mixed up rows and columns here. mRows should calculate the amount of horizontal character cells and mColumns the amount of vertical character cells :P

rowIndex and columnIndex names also seem to be mixed up.

You can fix both of those names here and in GetCharacterRegion if you want. If not, I'll change it myself in the future. It won't change the logic, it just will be clearer.

Only now i have realized that I mixed up rows and columns here. `mRows` should calculate the amount of horizontal character cells and `mColumns` the amount of vertical character cells :P `rowIndex` and `columnIndex` names also seem to be mixed up. You can fix both of those names here and in `GetCharacterRegion` if you want. If not, I'll change it myself in the future. It won't change the logic, it just will be clearer.
whou marked this conversation as resolved
whou left a comment
Copy link

The current changes don't work because of the mRows/mColumns name mix up (just see the texture_font_test to check).

If any of my explanations were confusing, here is the diff of your code with the fixed changes:

diff --git a/src/texture_font.cpp b/src/texture_font.cpp
index f25ba33..c8c5238 100644
--- a/src/texture_font.cpp
+++ b/src/texture_font.cpp
@@ -37,19 +37,21 @@ TextureFont::TextureFont(const std::weak_ptr<Texture> &fontTexture,
 }
 const auto texture = mFontTexture.lock();
 
- mRows = texture->width / (mCharWidth + horizontalSpacing);
- mColumns = texture->height / (mCharHeight + verticalSpacing);
+ mColumns = std::floor(texture->width / (mCharWidth + horizontalSpacing));
+ mRows = std::floor(texture->height / (mCharHeight + verticalSpacing));
 
- if (mColumns == 0) mColumns = 1;
+ if (mColumns == 0) {
+ mColumns = 1;
+ }
 }
 
 TextureRegion TextureFont::GetCharacterRegion(const char &c) const {
 const std::uint32_t charIndex = c - 32; // ASCII index
- const std::uint32_t columIndex = charIndex / mColumns;
- const std::uint32_t rowIndex = charIndex % mColumns;
+ const std::uint32_t rowIndex = std::floor(charIndex / mColumns);
+ const std::uint32_t columnIndex = std::floor(charIndex % mColumns);
 
- std::uint32_t x = rowIndex * (mCharWidth + mHorizontalSpacing);
- std::uint32_t y = columIndex * (mCharWidth + mVerticalSpacing);
+ std::uint32_t x = columnIndex * (mCharWidth + mHorizontalSpacing);
+ std::uint32_t y = rowIndex * (mCharHeight + mVerticalSpacing);
 return TextureRegion{
 mFontTexture,
 mOrigin.x + static_cast<float>(x),

If you want, just apply those fixes into you PR and commit again. Always remember to check if the texture_font_text renders the "Hello World!" text correctly before commiting :)

The current changes don't work because of the `mRows`/`mColumns` name mix up (just see the `texture_font_test` to check). If any of my explanations were confusing, here is the diff of your code with the fixed changes: ``` diff --git a/src/texture_font.cpp b/src/texture_font.cpp index f25ba33..c8c5238 100644 --- a/src/texture_font.cpp +++ b/src/texture_font.cpp @@ -37,19 +37,21 @@ TextureFont::TextureFont(const std::weak_ptr<Texture> &fontTexture, } const auto texture = mFontTexture.lock(); - mRows = texture->width / (mCharWidth + horizontalSpacing); - mColumns = texture->height / (mCharHeight + verticalSpacing); + mColumns = std::floor(texture->width / (mCharWidth + horizontalSpacing)); + mRows = std::floor(texture->height / (mCharHeight + verticalSpacing)); - if (mColumns == 0) mColumns = 1; + if (mColumns == 0) { + mColumns = 1; + } } TextureRegion TextureFont::GetCharacterRegion(const char &c) const { const std::uint32_t charIndex = c - 32; // ASCII index - const std::uint32_t columIndex = charIndex / mColumns; - const std::uint32_t rowIndex = charIndex % mColumns; + const std::uint32_t rowIndex = std::floor(charIndex / mColumns); + const std::uint32_t columnIndex = std::floor(charIndex % mColumns); - std::uint32_t x = rowIndex * (mCharWidth + mHorizontalSpacing); - std::uint32_t y = columIndex * (mCharWidth + mVerticalSpacing); + std::uint32_t x = columnIndex * (mCharWidth + mHorizontalSpacing); + std::uint32_t y = rowIndex * (mCharHeight + mVerticalSpacing); return TextureRegion{ mFontTexture, mOrigin.x + static_cast<float>(x), ``` If you want, just apply those fixes into you PR and commit again. Always remember to check if the `texture_font_text` renders the "Hello World!" text correctly before commiting :)
@ -40,2 +40,2 @@
mRows = std::floor(texture->width / (mCharWidth + horizontalSpacing));
mColumns = std::floor(texture->height / (mCharHeight + verticalSpacing));
mRows = texture->width / (mCharWidth + horizontalSpacing);
mColumns = texture->height / (mCharHeight + verticalSpacing);
Owner
Copy link

We do std::floor here because if the division ends up being closer to the ceiling than the floor C++ will implicitly round up when converting to an unsigned integer. This behavior may return the wrong amount of rows and causing bugs if the font text has more pixels than the minimum necessary.

Take the current assets/monogram-bitmap.png texture we test on for example: it is currently 96 pixels wide, the character width is 5 and the horizontal spacing between characters is 1, each row has 16 columns of characters. As it stands, it correctly calculates 96 / (5 + 1) = 16 and still implicitly correctly rounds down (without std::floor) to 16 until the user puts an image with a width of 99 (99 / (5 + 1) = 16.5 which will correctly round to 16).

But what happens if the user accidentally uses a texture with 4 extra pixels? texture->width will be 100 and the result will be 100 / (5 + 1) = 16.666 which will implicitly round up to 17. But that would be a bug, because that texture can't possibly contain 17 characters horizontally (with mCharWidth = 5 and horizontalSpacing = 1). To prevent that we always explicitly round down with std::floor.

Please keep the std::floor call around both of these lines.

We do `std::floor` here because if the division ends up being closer to the ceiling than the floor C++ will implicitly round up when converting to an unsigned integer. This behavior may return the wrong amount of rows and causing bugs if the font text has more pixels than the minimum necessary. Take the current `assets/monogram-bitmap.png` texture we test on for example: it is currently 96 pixels wide, the character width is 5 and the horizontal spacing between characters is 1, each row has 16 columns of characters. As it stands, it correctly calculates `96 / (5 + 1) = 16` and still implicitly correctly rounds down (without `std::floor`) to 16 until the user puts an image with a width of 99 (`99 / (5 + 1) = 16.5` which will correctly round to 16). But what happens if the user accidentally uses a texture with 4 extra pixels? `texture->width` will be 100 and the result will be `100 / (5 + 1) = 16.666` which will implicitly round up to 17. But that would be a bug, because that texture can't possibly contain 17 characters horizontally (with `mCharWidth = 5` and `horizontalSpacing = 1`). To prevent that we always explicitly round down with `std::floor`. Please keep the `std::floor` call around both of these lines.
whou marked this conversation as resolved
@ -42,0 +40,4 @@
mRows = texture->width / (mCharWidth + horizontalSpacing);
mColumns = texture->height / (mCharHeight + verticalSpacing);
if (mColumns == 0) mColumns = 1;
Owner
Copy link

Thanks for catching that possible divided by zero bug! I wouldn't have gotten that.

Although I would ask you to include explicit braces here and put mColumns = 1 in its own line. readability-braces-around-statements is a check enabled on .clang-tidy, and I personally prefer for it to be explicit.

Also my fault. I need to write some contributing guidelines and require clang-tidy checks.

Thanks for catching that possible divided by zero bug! I wouldn't have gotten that. Although I would ask you to include explicit braces here and put `mColumns = 1` in its own line. `readability-braces-around-statements` is a check enabled on `.clang-tidy`, and I personally prefer for it to be explicit. Also my fault. I need to write some contributing guidelines and require `clang-tidy` checks.
whou marked this conversation as resolved
@ -53,3 +48,1 @@
(rowIndex * mCharWidth) + (rowIndex * mHorizontalSpacing);
const std::uint32_t y =
(columnIndex * mCharHeight) + (columnIndex * mVerticalSpacing);
const std::uint32_t columIndex = charIndex / mColumns;
Owner
Copy link

Same possible rounding bug as mentioned before. std::floor should be kept.

I understood why you changed it to mColumns here, since it's calculating based on the columns. But that would end up being straight up incorrect code because I mixed up mRows and mColumns names before :P. If you decide to switch mRows and mColumns names everywhere else, you may keep mColumns here. Otherwise, keep the original mRows, as it would be a bug to not do so.

Also, you misspelled columnIndex as columIndex, but that is not as significant :)

Same possible rounding bug as mentioned before. `std::floor` should be kept. I understood why you changed it to `mColumns` here, since it's calculating based on the columns. But that would end up being straight up incorrect code because I mixed up `mRows` and `mColumns` names before :P. If you decide to switch `mRows` and `mColumns` names everywhere else, you may keep `mColumns` here. Otherwise, keep the original `mRows`, as it would be a bug to not do so. Also, you misspelled `columnIndex` as `columIndex`, but that is not as significant :)
whou marked this conversation as resolved
@ -54,2 +48,2 @@
const std::uint32_t y =
(columnIndex * mCharHeight) + (columnIndex * mVerticalSpacing);
const std::uint32_t columIndex = charIndex / mColumns;
const std::uint32_t rowIndex = charIndex % mColumns;
Owner
Copy link

Same std::floor and mColumns/mRows name switch comments here. Otherwise, thanks for the simplification, I would not have gotten that :)

Same `std::floor` and `mColumns`/`mRows` name switch comments here. Otherwise, thanks for the simplification, I would not have gotten that :)
whou marked this conversation as resolved
@ -56,1 +49,4 @@
const std::uint32_t rowIndex = charIndex % mColumns;
std::uint32_t x = rowIndex * (mCharWidth + mHorizontalSpacing);
std::uint32_t y = columIndex * (mCharWidth + mVerticalSpacing);
Owner
Copy link

You seemed to have misspelled here, mCharWidth should be mCharHeight :)

You seemed to have misspelled here, `mCharWidth` should be `mCharHeight` :)
whou marked this conversation as resolved
Author
First-time contributor
Copy link

Hello

thanks you very much for you review code so i will quickly fix this :)

Hello thanks you very much for you review code so i will quickly fix this :)
Author
First-time contributor
Copy link

okay so it's good normally i fix everything.

okay so it's good normally i fix everything.
whou left a comment
Copy link

Again, the correct diff of changes to apply to address my review concerns would be:

diff --git a/src/texture_font.cpp b/src/texture_font.cpp
index f117cff..c8c5238 100644
--- a/src/texture_font.cpp
+++ b/src/texture_font.cpp
@@ -37,8 +37,8 @@ TextureFont::TextureFont(const std::weak_ptr<Texture> &fontTexture,
 }
 const auto texture = mFontTexture.lock();
 
- mRows = static_cast<std::uint32_t>(std::floor(static_cast<float>(texture->width) / (mCharWidth + horizontalSpacing)));
- mColumns = static_cast<std::uint32_t>(std::floor(static_cast<float>(texture->height) / (mCharHeight + verticalSpacing)));
+ mColumns = std::floor(texture->width / (mCharWidth + horizontalSpacing));
+ mRows = std::floor(texture->height / (mCharHeight + verticalSpacing));
 
 if (mColumns == 0) {
 mColumns = 1;
@@ -47,11 +47,11 @@ TextureFont::TextureFont(const std::weak_ptr<Texture> &fontTexture,
 
 TextureRegion TextureFont::GetCharacterRegion(const char &c) const {
 const std::uint32_t charIndex = c - 32; // ASCII index
- const std::uint32_t columnIndex = static_cast<std::uint32_t>(std::floor(static_cast<float>(charIndex / mColumns)));
- const std::uint32_t rowIndex = static_cast<std::uint32_t>(std::floor(static_cast<float>((charIndex % mColumns))));
+ const std::uint32_t rowIndex = std::floor(charIndex / mColumns);
+ const std::uint32_t columnIndex = std::floor(charIndex % mColumns);
 
- std::uint32_t x = rowIndex * (mCharWidth + mHorizontalSpacing);
- std::uint32_t y = columnIndex * (mCharHeight + mVerticalSpacing);
+ std::uint32_t x = columnIndex * (mCharWidth + mHorizontalSpacing);
+ std::uint32_t y = rowIndex * (mCharHeight + mVerticalSpacing);
 return TextureRegion{
 mFontTexture,
 mOrigin.x + static_cast<float>(x),

Please run the available tests before commiting anything and make sure everything is behaving correctly. Sorry for being too pedantic, it's partly my fault for not having explicit contributions guidelines (never thought someone would care to even contribute tbh).

Again, the correct diff of changes to apply to address my review concerns would be: ``` diff --git a/src/texture_font.cpp b/src/texture_font.cpp index f117cff..c8c5238 100644 --- a/src/texture_font.cpp +++ b/src/texture_font.cpp @@ -37,8 +37,8 @@ TextureFont::TextureFont(const std::weak_ptr<Texture> &fontTexture, } const auto texture = mFontTexture.lock(); - mRows = static_cast<std::uint32_t>(std::floor(static_cast<float>(texture->width) / (mCharWidth + horizontalSpacing))); - mColumns = static_cast<std::uint32_t>(std::floor(static_cast<float>(texture->height) / (mCharHeight + verticalSpacing))); + mColumns = std::floor(texture->width / (mCharWidth + horizontalSpacing)); + mRows = std::floor(texture->height / (mCharHeight + verticalSpacing)); if (mColumns == 0) { mColumns = 1; @@ -47,11 +47,11 @@ TextureFont::TextureFont(const std::weak_ptr<Texture> &fontTexture, TextureRegion TextureFont::GetCharacterRegion(const char &c) const { const std::uint32_t charIndex = c - 32; // ASCII index - const std::uint32_t columnIndex = static_cast<std::uint32_t>(std::floor(static_cast<float>(charIndex / mColumns))); - const std::uint32_t rowIndex = static_cast<std::uint32_t>(std::floor(static_cast<float>((charIndex % mColumns)))); + const std::uint32_t rowIndex = std::floor(charIndex / mColumns); + const std::uint32_t columnIndex = std::floor(charIndex % mColumns); - std::uint32_t x = rowIndex * (mCharWidth + mHorizontalSpacing); - std::uint32_t y = columnIndex * (mCharHeight + mVerticalSpacing); + std::uint32_t x = columnIndex * (mCharWidth + mHorizontalSpacing); + std::uint32_t y = rowIndex * (mCharHeight + mVerticalSpacing); return TextureRegion{ mFontTexture, mOrigin.x + static_cast<float>(x), ``` Please run the available tests before commiting anything and make sure everything is behaving correctly. Sorry for being too pedantic, it's partly my fault for not having explicit contributions guidelines (never thought someone would care to even contribute tbh).
@ -40,2 +40,2 @@
mRows = std::floor(texture->width / (mCharWidth + horizontalSpacing));
mColumns = std::floor(texture->height / (mCharHeight + verticalSpacing));
mRows = static_cast<std::uint32_t>(std::floor(static_cast<float>(texture->width) / (mCharWidth + horizontalSpacing)));
mColumns = static_cast<std::uint32_t>(std::floor(static_cast<float>(texture->height) / (mCharHeight + verticalSpacing)));
Owner
Copy link

These lines do not respect the 80 columns default limit imposed by clang-format, no big deal there though. But clang-tidy rightfully points out narrowing conversions in the static_casts here. The original code does not have different types on both sides of the division, so no static_cast is needed, and as clang-tidy points out, it might make a narrowing conversion to happen. So remove those.

The code base has both .clang-tidy and .clang-format files in it. Please use them and always run clang-tidy and clang-format before commits and apply the suggested fixes. It keeps the style and opinions about conventions and formatting consistent across the code.

If it's a truly nonsensical thing clang-tidy is complaining about, you can ignore it inline or in .clang-tidy/.clang-format and argue why it would be better to ignore it. I already do ignore a ton of stuff on there, but I quite like the majority of the defaults. But nothing that clang-tidy is saying here is nonsensical.

Most importantly, you did not address the rows/columns naming confusion (that was present prior to your changes) that causes the calculations to simply not work after your changes. I already addressed them and where exactly you should change them for the code to work. But as it stands this code does still not work. The texture_font_test still incorrectly renders the "Hello World" text. Simply addressing the rows/columns naming confusion makes it work again.

It seemed like you again did not test your changes before commiting code. Please always run the tests relevant to the changes to make sure your code does work as intended before commiting.

These lines do not respect the 80 columns default limit imposed by clang-format, no big deal there though. But clang-tidy rightfully points out narrowing conversions in the `static_cast`s here. The original code does not have different types on both sides of the division, so no `static_cast` is needed, and as clang-tidy points out, it might make a narrowing conversion to happen. So remove those. The code base has both `.clang-tidy` and `.clang-format` files in it. Please use them and always run `clang-tidy` and `clang-format` before commits and apply the suggested fixes. It keeps the style and opinions about conventions and formatting consistent across the code. If it's a truly nonsensical thing clang-tidy is complaining about, you can ignore it inline or in `.clang-tidy`/`.clang-format` and argue why it would be better to ignore it. I already do ignore a ton of stuff on there, but I quite like the majority of the defaults. But nothing that clang-tidy is saying here is nonsensical. Most importantly, you did not address the rows/columns naming confusion (that was present prior to your changes) that causes the calculations to simply not work after your changes. I already addressed them and where exactly you should change them for the code to work. But as it stands this code does still not work. The `texture_font_test` still incorrectly renders the "Hello World" text. Simply addressing the rows/columns naming confusion makes it work again. It seemed like you again did not test your changes before commiting code. Please *always* run the tests relevant to the changes to make sure your code does work as intended before commiting.
@ -54,2 +50,2 @@
const std::uint32_t y =
(columnIndex * mCharHeight) + (columnIndex * mVerticalSpacing);
const std::uint32_t columnIndex = static_cast<std::uint32_t>(std::floor(static_cast<float>(charIndex / mColumns)));
const std::uint32_t rowIndex = static_cast<std::uint32_t>(std::floor(static_cast<float>((charIndex % mColumns))));
Owner
Copy link

Same three points discussed before also apply here. clang-format, clang-tidy and rows/columns naming. Run the tests before commiting.

Same three points discussed before also apply here. clang-format, clang-tidy and rows/columns naming. Run the tests before commiting.
Author
First-time contributor
Copy link

okay i will fix this thanks you for your review :)

okay i will fix this thanks you for your review :)
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u fix-calculus-bug:drex_vk-fix-calculus-bug
git switch drex_vk-fix-calculus-bug

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff drex_vk-fix-calculus-bug
git switch drex_vk-fix-calculus-bug
git rebase main
git switch main
git merge --ff-only drex_vk-fix-calculus-bug
git switch drex_vk-fix-calculus-bug
git rebase main
git switch main
git merge --no-ff drex_vk-fix-calculus-bug
git switch main
git merge --squash drex_vk-fix-calculus-bug
git switch main
git merge --ff-only drex_vk-fix-calculus-bug
git switch main
git merge drex_vk-fix-calculus-bug
git push origin main
Sign in to join this conversation.
No reviewers
Labels
Clear labels
No items
No labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
whou/wack!2
Reference in a new issue
whou/wack
No description provided.
Delete branch "drex_vk/wack:fix-calculus-bug"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?