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

Author Topic: View zoom and text  (Read 3242 times)

0 Members and 1 Guest are viewing this topic.

Garwin

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
View zoom and text
« on: April 05, 2023, 10:36:08 pm »
I would like to create world map which has a lot of labels. This map can be rotated, moved and zoomed and for that view is perfect. However these labels should not be zoomed.

What can be best solution with SFML?

I am thinking to have the second view for these labels only. However it means, that view cannot use zoom. That zoom must be transferred to move relating to the position of center of the view and applied individually to the texts and view applied on the text can use same moving as world map view and rotation skipped.

Another idea is to use transform matrix on position of object with world map view to get pixel on screen and than render text on that position.

Or is there another better way to do it?

« Last Edit: April 05, 2023, 10:47:31 pm by Garwin »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: View zoom and text
« Reply #1 on: April 07, 2023, 12:29:17 pm »
Having text scale and move smoothly with a zooming and moving map is not a trivial task, so it will always require a bit of math for the positioning.
The most important part about text rendering is, to not scale the text itself, otherwise you get blurry text. When you want to make text bigger, you need to scale the font size instead. You may get away with making large text smaller, but it can still introduce artifacts and unclean text boundaries.

Personally, I'd probably go with a separate view and calculate the position and size of each text to be perfectly matching the objects in the map. It gives complete control over the sizing of the text, and you don't have to adjust for world zoom/rotation etc.
Plus it also allows you to focus on texts that are currently visible.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Garwin

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: View zoom and text
« Reply #2 on: April 07, 2023, 02:40:42 pm »
Personally, I'd probably go with a separate view and calculate the position and size of each text to be perfectly matching the objects in the map. It gives complete control over the sizing of the text, and you don't have to adjust for world zoom/rotation etc.
Plus it also allows you to focus on texts that are currently visible.

I am trying to prototype this world's behavior. The moving entities work fine and the text is as it should be - placed over the top left corner with offset relating to the text size.

sf::Vector2f transformText (const sf::Vector2f& position, const sf::RenderWindow& window, const sf::View& viewFrom, const sf::View& viewTo)
{
    sf::Vector2i positionInWindow = window.mapCoordsToPixel (position, viewFrom);
    return window.mapPixelToCoords (positionInWindow, viewTo);
}

text2.setPosition(transformText(entity2.getPosition() + textOffset, window, mainView, textView));
 

When I tried to start zooming and rotating the view, the text follow the entity's left corner, however, as the entity is rotating the top left corner is not the top left anymore so with 180° rotation the text is under the entity.

I understand that I need to take the entity to apply the transformation of the view and get the bounding box of the entity and use the top left corner as a place for the text before offset.

Can SFML help me with that? The function transformText transforms a single coordinate but I need the whole entity to get global bounds. Can I achieve that without making a shadow copy of the entity to just have this entity with view transformation to achieve global bounds and that top left corner?

note: the whole prototype is in the attachment


Garwin

  • Jr. Member
  • **
  • Posts: 59
    • View Profile
Re: View zoom and text
« Reply #3 on: April 10, 2023, 12:56:34 am »
I used this for CircleShape. It works fine.

sf::Vector2f getPositionForText (const sf::CircleShape& shape,
                                                  const sf::RenderWindow& window,
                                                  const sf::View& viewFrom,
                                                  const sf::View& viewTo)
{
    float radius = shape.getRadius();
    sf::Vector2f center {shape.getPosition().x, shape.getPosition().y};
    sf::Vector2i positionInWindow = window.mapCoordsToPixel(center,viewFrom);
    center = window.mapPixelToCoords (positionInWindow, viewTo);
    center += sf::Vector2f {-radius * shape.getScale().x, -radius * shape.getScale().y}
                         * (viewTo.getSize().x / viewFrom.getSize().x);
    return center;
}

// and calling this function

text3.setPosition(getPositionForText(entity2, window, mainView, textView)
     + sf::Vector2f{0.f, -textSpaceHeight}); // text offset
 

Thinking about doing similar for any sf::Shape or VertexArray. I am thinking about 2 ways:
1. through bounding box
- getting sf::FloatRect bounding box of the entity
- transform between views using sf::Transform
- getting a new bounding box from a transformed bounding box
Advantages: relatively simple and probably reasonably fast
Disadvantages: position of text will be simplified as in the bounding box from the transformed bounding box could be large, especially if the transformed bounding box is at 45°.
2. through transforming entity
- copy entity
- transform entity between views
- finding the bounding box from the transformed entity
Advantages: Much more precise as the bounding box is found on top of transformed entity
Disadvantages: If there are many text labels over an entity it practically make no sense for the view and all these entities need to be copied transformed one by one