Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - abcd1234567

Pages: [1] 2
1
General / Re: Zooming in and out makes line flicker
« on: January 03, 2024, 06:39:43 pm »
Good to hear that your problem has been fixed. :)

Not sure if it's "fixed" as such though. If you're drawing lines, they will always be there and never flicker. The quads are being "hidden" by those lines and 'may' be exposed on other occasions where the lines are on the edge of a pixel.

I'm not sure I under what you mean by drawing the quads because you want them to be clickable. You can, of course, just test the rectangle area for mouse positions. And, if you mean that you need it to display something when it's clicked (or hovered over), you can simply draw those cells that need to have something. This means you can not draw the others. You can do this by resizing the vertex array after calculating how many cells will be displayed and then just adding those ones.

Since your grid is so strict and even, it should be simple enough to calculate if one of those is outside of the window. Indeed, you can use rectangle collision to check this (SFML's FloatRects can do this; it's called intersects). Check the cell's rectangle against the window's rectangle (actually the view's rectangle).
Then, combining with the things I mentioned in the previous paragraph, you can only draw to the cells in range (by resizing and only adding the ones that are in range).


As an aside, if you would like to use a tile map that can do this automatically, you could try:
https://github.com/Hapaxia/CheeseMap/wiki
(https://en.sfml-dev.org/forums/index.php?topic=29172.0)
You could use Cheese Map to display your map and then draw the lines around it.
It automatically "culls" cells outside of the view. You can also have de-activated cells that aren't displayed if you'd like.

I'm afraid I don't fully understand what you're saying in the 3rd and 4th paragraphs.
I have a huge grid (so that it "looks" infinite), which is clickable (you click on a cell and it changes color), and I have a view. I only draw what is in view.

Currently I simply hold a set of "clicked" cells (sparse matrix, if you will), and each frame I simply iterate over all cells in view, and check for each one if it is "clicked" - if yes, I draw it in color. If not - I leave it blank.

I am able to this since I'm holding an unordered_set (hash map), but vertexArray is just...an array. So for every cell (in view) I need to check the entire array from start to finish. Not very efficient.

Also, you said "you can simply draw those cells", did you mean drawing with quads?
I can't see a way to implement a clickable grid with just lines

Thanks in advance

2
General / Re: Zooming in and out makes line flicker
« on: January 02, 2024, 09:23:32 pm »
A vertex array allows you to draw many triangles at once rather than a couple (or so) at a time (like for a rectangle shape) so improves performance. It doesn't, however, change the way those triangles are calculated so vertex arrays don't automatically solve floating point ambiguities.

You would still need to apply a method (one or more I mentioned above or maybe something else you can find or think of!) to overcome those issues.

Thank you for the help.

It seems that moving to VertexArray did solve this problem for me, as seen here, the lines are not flickering:
https://streamable.com/0p825x
This is basically a VertexArray of Quads and a separate VertexArray of lines (I want the cells to be clickable, so lines are not enough)

But - is there a way to show only the vertices in view? Of course, the more the array grows - such is the draw time, so a grid of 1024x1024 cells (each 32x32) is already slow (drawing the quads+lines takes about 50ms).
I Googled it and found in old threads that it shouldn't be the bottleneck, and with VertexArray - it's drawing everything or nothing. How can I solve this?


3
General / Re: window.display() is very slow with vertex array
« on: January 02, 2024, 08:27:08 pm »
I tested it as-is and only experienced time output (to console) of zero, sorry.

Oh, but I did notice that I don't think your squares are what you think they are.
Remember to multiply every component with CELL_SIZE. ;)
It shouldn't affect what display is doing but it should make what you see an actual grid of squares.
If you change the first vertex to this line, the error is a little more obvious:
va.append({ sf::Vector2f((float)j * CELL_SIZE, (float)i * CELL_SIZE), sf::Color::Red });

Of course, my mistake.
But how peculiar, when changing it to the correct way (multipling every component with CELL_SIZE), the problem is resolved.

Before the change:


After the change:


Well, thanks a lot :>

4
General / Re: window.display() is very slow with vertex array
« on: January 02, 2024, 03:17:44 pm »
What platform are you on? Make sure your GPU drover is up-to-date.

Windows 10, i5 gen 10 CPU with GTX 1650 GPU. Just updated my GPU drivers, and the problem persists :<

5
General / window.display() is very slow with vertex array
« on: January 01, 2024, 07:16:00 pm »
I'm trying to run a small piece of code, just to get familier with VertexArray:
#include <iostream>
#include <SFML/Graphics.hpp>

using namespace std;

#define CELL_SIZE 32

void fillVertexArray(sf::VertexArray& va, int num_of_squares_x, int num_of_squares_y){
    for (int i = 0; i < num_of_squares_y; i++){
        for (int j = 0; j < num_of_squares_x; j++){
            va.append(sf::Vector2f((float)j * CELL_SIZE, (float)i * CELL_SIZE));
            va.append(sf::Vector2f((float)(j + 1) * CELL_SIZE, (float)i));
            va.append(sf::Vector2f((float)(j + 1) * CELL_SIZE, (float)(i + 1) * CELL_SIZE));
            va.append(sf::Vector2f((float)j, (float)(i + 1) * CELL_SIZE));
        }
    }

}

void printLogTime(sf::Clock& code_timer, bool reset){
    if (reset) code_timer.restart();
    else std::cout << code_timer.getElapsedTime().asMilliseconds() << std::endl;
}

int main() {
    sf::VertexArray va(sf::PrimitiveType::Quads);
    fillVertexArray(va, 32, 32);

    sf::RenderWindow window(sf::VideoMode(1440, 810), "SFML test", sf::Style::Default);
    float zoom = 1;
    sf::View view = window.getDefaultView();
    sf::Clock code_timer;

    while(true){
        sf::Event evnt;
        while (window.pollEvent(evnt)){
            switch(evnt.type){
                case sf::Event::Closed:
                    return -1;

                case sf::Event::MouseWheelScrolled:
                    // &#39;zoom()&#39; is by a factor. a number greater than 1 means zoom-out; a number smaller than 1 means zoom-in.
                    if (evnt.mouseWheelScroll.delta <= -1) { // Scroll down - zoom-out
                        zoom = std::min(2.0, zoom + 0.1); // By using &#39;min&#39; with &#39;2&#39;, we set it as a lower limit.
                    }
                    else if (evnt.mouseWheelScroll.delta >= 1) { // Scroll up - zoom-in
                        zoom = std::max(0.5, zoom - 0.1); // By using &#39;max&#39; with &#39;0.5&#39;, we set it as an upper limit.
                    }

                    // We use &#39;setSize()&#39; here to reset our view (by setting it to the default view&#39;s size).
                    // Why? Because, as we&#39;ve said, &#39;zoom()&#39; is by a factor. So if we zoomed twice we&#39;d be multiplying instead of adding.
                    // For that we reset the view and then apply the zoom on it.
                    view.setSize(window.getDefaultView().getSize()); // Reset the size
                    view.zoom(zoom);
                    window.setView(view);
                    break;
            }
        }

        window.clear();
        window.draw(va);
        printLogTime(code_timer, true);
        window.display();
        printLogTime(code_timer, false);
    }

    return 0;
}
 

But when logging I get that every window.display() call takes about ~40 milliseconds.
When deleting the 'window.draw(va)' line, it drops down to 0 milliseconds (rounding).
For comparison, in another project where there's a LOT of shapes on screen, it's also about 0 milliseconds, so I don't understand the sudden spike here, considering VertexArray should be very efficient

6
General / Re: Zooming in and out makes line flicker
« on: January 01, 2024, 04:36:47 pm »
Moving to a vertex array is almost always the answer ;D
It's the ability to display multiple quads/triangles at once so much fewer draw calls for multiple rectangle shapes.
Of course, a tile map is just a vertex array at heart but designed to draw tiles.

My point was that even by only scaling double and half, keeping to integers still brings complications.
Scaling by anything else can be even more complications.

The consideration really is if you can put up with slight gaps. If not, you'll need a technique to reduce it:

Not scaling is one.

"Over-drawing" is another: drawing the tiles bigger than they should be so that they overlap.

Drawing at an integer-perfect state on a render texture and then drawing the render texture with modifications that would normally cause the gaps (there can be no gaps because it's already been rendered without them on the render texture).
This is a bit of work and can still be an issue when scaling if not handled carefully.

Using larger tiles can reduce issues too; Less likely to have gaps if there aren't tiles. Building a map of full pieces can a reliable way but removes the convenience of repeatable tiles.

Hey, sorry for the bump, I'm trying to get back to this after I've experienced a bit more with SFML.
I've read about vertexArray in the doc, and I just want to know one thing:

Performence is not my main concern - despite drawing a lot of sf::RectangleShape to make the grid, I'm only drawing the ones in view, so draw() cost almost nothing (from testing).

I want to move to VertexArray mainly to solve this zoom issue, when lines flicker in and out of existence when zooming. Do you think it would solve it?

7
General / Re: Slight differences with Text object position
« on: December 25, 2023, 10:10:02 am »
Each character has a separate quad generated. The quads are different sizes depending on the look of the character. When you set the position, this is the top left of the region characters could be in, but getGlobalBounds returns the actual rectangle that fits the visible characters. So the bounds will change if you change the text. If you just had a bunch of short characters (like "mmmm") the top bounds would be even further down.

Is it possible to know in advance, just based on my setPosition() and characterSize, the bounds of a rectangle that would contain the Text object?

My problem is this:

#include <iostream>
#include <SFML/Graphics.hpp>

int main() {
    sf::Font font;
    if (!font.loadFromFile("arial.ttf")){
        exit(-1);
    }
    sf::Text str("GoodBye", font, 20);
    str.setPosition(0,0);
    sf::FloatRect global_rect = str.getGlobalBounds();
    std::cout << "top: " << global_rect.top << " height: " << global_rect.height << std::endl;

    return 0;
}
 

I set the position in (0,0) with characterSize of 20. But top is 5 and height is 19.
Basically, a rectangle with top-left (0,0) and height of 20 won't contain the Text object.

For reference: I'm writing a menu in which there's Text objects stacked above each other, and I want each one of them to be in a fixed size rectangle.

8
General / Slight differences with Text object position
« on: December 24, 2023, 09:35:44 pm »
I'm having sligt differences between the positions I set my Text object and where they are in the 2D world (according to getGlobalBounds).
Lets take a look at the following simplified code:

#include <iostream>
#include <SFML/Graphics.hpp>

int main() {
    sf::Font font;
    if (!font.loadFromFile("arial.ttf")){
        exit(-1);
    }
    sf::Text str("Hello!", font, 30);
    str.setPosition(0,0);
    sf::FloatRect global_rect = str.getGlobalBounds();
    sf::RenderWindow window(sf::VideoMode(640, 480), "Window");

    while(window.isOpen()){
        window.clear();
        window.draw(str);
        window.display();
    }

    return 0;
}
 

If you would check the top and left values of global_rect, it would be 2 and 8 respectively, instead of 0 and 0, despite setting the top-left corner to be at (0,0). Why is that?

9
General / Re: What is a good way to draw a really long list of text?
« on: December 24, 2023, 09:30:49 pm »
Multi-line does allow fewer draw calls and that can help with performance.

My point about cells was that you can implement it as if it was a table of cells regardless of the width of each text/item. This means that you would consider it "hovering" an item if its within that "cell" rectangle even if it isn't over the actual text itself.
If you think of it as a table of cells that is wide enough to contain all of the text lengths and each of the smaller ones would just be inside a wider cell.

With the render texture idea, you would need to track which the rectangles when drawing them.
The process for render texture, by the way, would be to draw them all to the render texture once. Then, use that texture to draw a quad/rectangle that displays it (and all those texts). You can draw that simple rectangle every frame but you shouldn't need to update the texts in the render texture at all if they don't change (so don't draw them every frame).

With multi-line, again you could keep a separate track of rectangles. Or, you could divide its entire height by its "line spacing". That should give you a decent approximation of where lines are.
Or, you could also try this:
https://github.com/SFML/SFML/wiki/Source%3A-Get-Character-At-Coord
(it tells you which character in a text is at a specific position) but the longer the text, the longer it might take to search (if further in the text). It shouldn't be too significant a delay but you can try it and see if it's what you might be looking for.

Amazing, thanks a lot!

10
General / Re: What is a good way to draw a really long list of text?
« on: December 24, 2023, 08:16:45 pm »
As soon as you have hundreds of texts, you should be considering options to reduce this number.

If you have static texts (that don't change the content very often), consider pre-rendering to a render texture. You can still move them around but they will move together.

Aside from that, and more specifically to your scenario, the first thing I would suggest is to work out which texts are not on screen. You can use this for two significant improvements:
1) you can only check those ones for "collision" with visible user interface points (such as a mouse position)
2) you can draw only those ones. this can significantly decrease frame time (improve frame rate) if you have so many draw calls.

I suspect you are still using a single text object per line due to the fact that you seem to be centring them and you cannot do this to a multi-line block in SFML. (not yet, anyway, but I have proposed an implementation of this already ;) )

So, if you have a long list of things, draw them all (or in groups) to a render texture (maybe a few) and then move and draw just the render texture(s) once.

In addition, to check if your mouse is over a specific text, you could consider approximate rectangles. These would be around the text but not "pixel-exact". This might even be prefered for usability due to the ease of being able to select something without having to exactly on it. You could, for example, break up the list into rectangles that are about the height of the difference in y positions (basically this means that you would always be over one of the texts) and equal widths. Equal widths are often used in these sorts of scenarios. Consider thinking about it like a table of cells. Then, you can simply check if the mouse is inside the cell rather than deal with the text graphic itself.

The menu doesn't change at all. The user clicks on an option and we move to a different menu. Basically, you're saying that drawing a RenderTexture (which to itself I drew all the texts) in my window is faster than drawing those texts directly to the window? Is that because I'm esentially just drawing a "picture" of those texts, and the objects themselves?

Thanks for the tips, I'll be sure to implement it :)

I don't mind the text being left-oriented, as long as it helps with performance ;) If I understand correctly, the multi line solution is similar to the RenderTexture, no? Draw just a single object instead all of them. Although since I want to have hover functionality, how can it work when I have just one Text object or one RenderTexture object? For that reason I also don't think I could draw only once

Oh I wish it was like a table of cells  :P But the widths would be different, since the filenames are of different lengths. You can see how that affects the hover functionality

11
General / Re: What is a good way to draw a really long list of text?
« on: December 24, 2023, 05:46:09 pm »
Every character can have a wildly separate width, that's true. It's mainly dependent on the font but should be considered in code for any font.

You "clip" a text to a specific size, you can set its string and see how wide it is without drawing it.
You can then remove a character one at a time until its width becomes within range.

That's the simplest method. However, you can use sf::Text's findCharacterPos method to see how far along the x axis each character is and then just cut the string to match the result.

One you've cut all the lines to how you want them, don't forget you can have a text with multiple lines by adding the newline character ('\n') between them.
You can even specify the distant between the lines to help aid with layout using setLineSpacing.

Thanks a lot!
If you don't mind, I'd be happy if you could help me with another issue:
I've decided to move to simply a scrollable list of items that looks like this:


Basically it's just one screen that you can scroll to the bottom.
Now, I want to be able to color the menu item when the user hovers above it, and want to be able to register that item when the user has pressed on it.

Problem is: as we've seen, every Text object has a different height.
So when I register a click, I have no way of knowing if it was inside a Text object or not,
outside than to run through all of them with the Contains function.

Of course, if we want to implement hover functionality, which we check for in every iteration of the loop, then it's just too slow to check every single object every iteration; since the amount of Text objects can reach the hundreds in my program.

Is there a better way of doing it?




12
General / What is a good way to draw a really long list of text?
« on: December 24, 2023, 01:30:49 pm »
I have a game, and in its starting menu I want to display all filenames from specific folders (so that the user can choose a filename to load and thus start the game). Something along the lines of:



Only Each folder/category would take it's own screen (there's a LOT of filenames)

I want each text object to be in its own "width bounds" so that it's evenly spaced.
Any filename that would exceed this width bound would be ignored.

And that is where I'm stuck. Basically, I don't know how can I know the local bounds that the string would have just from looking at it (and the intended font size). For example, the string "A" with font size 30 gives me width of 15 (when checking with getLocalBounds), but the string "P" with same font size gives width of 19. Same goes with height - it just seems unpredictable.

Thanks in advance, and if you have a better idea on who I should implement this, I would like to hear it  :)


13
General / Re: Zooming in and out makes line flicker
« on: November 13, 2023, 08:52:30 pm »
Moving to a vertex array is almost always the answer ;D
It's the ability to display multiple quads/triangles at once so much fewer draw calls for multiple rectangle shapes.
Of course, a tile map is just a vertex array at heart but designed to draw tiles.

My point was that even by only scaling double and half, keeping to integers still brings complications.
Scaling by anything else can be even more complications.

The consideration really is if you can put up with slight gaps. If not, you'll need a technique to reduce it:

Not scaling is one.

"Over-drawing" is another: drawing the tiles bigger than they should be so that they overlap.

Drawing at an integer-perfect state on a render texture and then drawing the render texture with modifications that would normally cause the gaps (there can be no gaps because it's already been rendered without them on the render texture).
This is a bit of work and can still be an issue when scaling if not handled carefully.

Using larger tiles can reduce issues too; Less likely to have gaps if there aren't tiles. Building a map of full pieces can a reliable way but removes the convenience of repeatable tiles.

I see, maybe I'll pass on the idea of implementing 'zoom' for now, as I'm only beginning with SFML.
Thaks a lot :)

14
General / Re: Zooming in and out makes line flicker
« on: November 13, 2023, 09:00:04 am »
Are the lines created by the rectangle shape's outline?
This would mean that the rectangles and their outlines are competing for pixels as they shrink.

"Keeping to integers" can be tough when scaling. To be exact, you'd need to always scale the view by half/double and then round to similar (when a view is scaled up to double so that everything is half-sized, you need to round to double values.
e.g. if you are drawing at (1, 1) and scale the view so that that point would be (0.5, 0.5), you need to draw at (2, 2) instead so that the point would be (1, 1).

Yes, the lines are created by the rectangle shape's outline
Would you suggest to move on to tileMap or Vertex array?

Scaling only by half/double seems like too much :<

15
General / Zooming in and out makes line flicker
« on: November 12, 2023, 11:23:47 pm »
Sorry for double-posting, I'm having a problem understanding the solution to this.
When zooming in and out of a grid, I see that lines would disappear, as seen in the video below:
https://streamable.com/e0bd53

I googled the problem and found in an old thread here that the problem is setting the view to non-integer values. Makes sense. But how can I set the view to integer values in this case? All I do is call the 'zoom' function, I'm not moving the view or anything, that I can round my values.

Here is the "zoom event" in the event loop:
case sf::Event::MouseWheelScrolled:
                    if (evnt.mouseWheelScroll.delta <= -1) // Scroll down - zoom-out
                        zoom = std::min(2.0, zoom + 0.1); // By using &#39;min&#39; with &#39;2&#39;, we set it as a lower limit.
                    else if (evnt.mouseWheelScroll.delta >= 1) // Scroll up - zoom-in
                        zoom = std::max(0.5, zoom - 0.1); // By using &#39;max&#39; with &#39;0.5&#39;, we set it as an upper limit.

                    view.setSize(window.getDefaultView().getSize()); // Reset the size
                    view.zoom(zoom);
                    window.setView(view);
                    break;

And just for reference, here is the draw function:
void drawGrid(sf::RenderWindow& window, std::unordered_set<sf::Vector2i, pair_hash, pair_equal>& grid){
    sf::RectangleShape cell(sf::Vector2f(CELL_SIZE, CELL_SIZE));
    cell.setOutlineColor(sf::Color(200, 200, 200)); // Beige
    cell.setOutlineThickness(1.25);
    for (int i = 0; i < GRID_HEIGHT / CELL_SIZE; i++){
        for (int j = 0; j < GRID_WIDTH / CELL_SIZE; j++){
            if (grid.count({j,i})) cell.setFillColor(LIVE_CELL_COLOR);
            else cell.setFillColor(DEAD_CELL_COLOR);

            // Set cell position based on its grid coordinates.
            cell.setPosition(j * CELL_SIZE, i * CELL_SIZE);
            window.draw(cell);
        }
    }
}

Thanks in advance.

Pages: [1] 2