I am making some classes to help create a GUI using SFML. I would like to be able to display only a part of a sf::Text. Something like setTextureRect in the sf::Sprite class.
The only solution I found was to draw the text to a sf::RenderTexture and then I assign its texture to a sprite. I can then draw this sprite on the window.
//The class contains :
sf::RenderTexture buffer;
//When the class is created :
buffer.create(window.getSize().x,window.getSize().y);
//To draw on the screen :
window.clear();
buffer.clear();
buffer.draw(text);
buffer.display();
sprite.setTexture(buffer.getTexture());
window.draw(sprite);
window.display();
This allows me to use sf::Sprite::setTextureRect, but it is very slow. I measured that it is about 100 times slower than a direct draw. I tried creating the buffer to the size of the text but it had almost no impact on the performance.
So my question is, is there a way to display only a part of a sf::Text (or sf::Shape) that would be more efficient?
You can use sf::View to determine what is drawn and what not.
Remember that the rectangle that is drawn, with respect to the window, use the range 0.f - 1.f.
The tutorials can help.
As you saw, there's no method to do this in sf::Text.
http://www.sfml-dev.org/documentation/2.3.1-fr/classsf_1_1Text.php
However, if as you said, you want to do this: http://i.imgur.com/FsvnP.png
You can compute the size of the sf::Text and cut it before it exceeds the size of the frame (and eventually replace the last characters).
For example, "Person 2554548747848874874" will be "Person 25545..".
It's smooth and a lot of list are done this way. (You have an example with the Windows task explorer)
As DarkPhantom said, there's also sf::View, but you'll have to try to see if it's reliable to do a lot of setView().
Related
i've tried to make a project, but i can't draw a sprite as i want. I mean that everything works when i just draw a sprite, but it stop working when i am trying to draw the sprite by clicking left mouse button. There's code i tried:
if(zdarzenie.type == Event::MouseButtonPressed && zdarzenie.mouseButton.button == Mouse::Left)
{
pocisk.setPosition(10, 10);
oknoAplikacji.draw(pocisk);
}
Btw, I am writing in Polish as if it would change something.
And yes, i have everything good besides that.
(and i am using 2.4.1 version of SFML)
I don't know what you are doing now because you didn't provide enough of your code and I actually don't understand your if statement but, it can just be :
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sprite.setPosition(sf::Mouse::getPosition());
renderTarget.draw(sprite);
}
By the way I strongly suggest that you do not use the draw function here but organize your code to have a draw method called in a render loop, because depending on where your code is in your program, the sprite could be drawn for only one frame and then erased since it's not updated.
From what I understand in your code in Polish, you have the right code to do what you want, but the problem comes from the fact that you draw the sprite only once.
The draw method is called every frame and it will erase everything on screen and then redraw them. Doing it only once, like in your code, will only draw it a single time then delete it the very next frame.
At that point multiple solution can be used. If its a GameObject clicking can activate the object to then draw it or a simple bool could be used has a switch in your draw to make it appear.
I am trying to create a simple platformer game in C++ with SDL, although am having trouble implementing animated sprites into the game. Linked is my git repo.
As you will see i'm currently having difficult trying to draw a single portion of the sprite sheet as the player sprite and looping through it to animate it. At the moment the entire sprite sheet that contains the player sprites is being squished into a 32 pixel rectangle. I have looked into SDL_RenderCopy although changing the variables that I pass to the method has no affect.
https://github.com/mountainfolks/Platformer_SDL
Have you stepped through your code to see which draw call you're hitting? AnimatedSprite inherits from Sprite, but you don't have Draw set as virtual in the base class, so you're actually calling Sprite::Draw. That would explain the behavior that points to the source rectangle being null.
I was wondering whether the following can be easily implemented in OpenGL:
divide window into multiple panels
put each panel into place using normalized coordinates (0-1) so that if the window gets re-sized, the panel will stay in the correct position
draw directly into one of the previously defined panels
The result should look something like the following picture:
So far I've been drawing my objects directly into the window, offsetting the coordinates with the respective value for each panel. However this doesn't feel like the right way of doing things. Any suggestions and example code from experienced developers is highly appreciated!
EDIT: What I've read so far, using glScissor or glViewport might be two ways of accomplishing what I want, however I don't know what the pros and cons are for going either route (your insights are very welcome!). Additionally, I would really prefer to define some kind of panel, return its handle and just draw into that.
If you use glScissor() you just define the clipping rectangle (i.e. where to draw). This might be everything you need.
With glViewport() you essentially call glScissor() behind the scenes as well as changing how coordinates are mapped to screen space.
If you want to limit drawing to one of the panels (without using local coordinates), use glScissor(). Otherwise, use glViewport().
As for the panel, I'd probably use some abstract base class:
class Panel {
// ...
virtual void OnDraw(void) = 0;
void Draw(void) {
glViewport(x, y, w, h);
OnDraw();
glViewport(0, 0, parent_w, parent_h);
}
}
I wrote an app that uses Cairo to draw things on screen (on a Gtk::DrawingArea, to be exact). It needs to redraw everything frequently. It turns out, that despite the draphics drawn are very simple, the X server uses LOTS of CPU when redrawing, and the applications works terribly slow. Is there any way to speed this up? Or maybe I shouldn't use DrawingArea and some other widget?
What I draw is set of rectangles, which user can move around by dragging them with mouse. The whole drawing is done withing on_expose_event, but as the mouse pointer moves around (with button pressed), I call queue_draw() to refresh drawing.
Just a couple things to check:
Is your drawing done in the expose event?
Draw your image to a Cairo Surface, and then in the expose event simply copy from that surface to the widget's surface.
Are you clipping and drawing only the region necessary?
The expose event gives you an X, Y, width, height of the area that needs to be redrawn. In cairo, create a rectangle on your surface with these dimensions and call clip so that you aren't wasting time redrawing stuff that doesn't need to be.
Drawing is expensive, especially text drawing has become the most CPU expensive task of a GUI.
The only way to speed this up is to reduce the amount of drawn items. Check if you really only draw the items that are necessary. The expose-event is giving you a rectangle. Only refresh this part of the widget.
Maybe cache items in a bitmap.
For smooth scrolling for example it can help to draw the content into a bitmap that is for example 500 pixels larger so that in most cases you just need to copy the image and don't draw anything at all (you usually get expose rectangles that are just 5 to 10 pixels high during scrolling).
But you need to give us more information what you are drawing and what the system load is to get a better answer.
I found this article about threaded drawing in cairo to solve the speed-problem, maybe that helps:
http://cairographics.org/threaded_animation_with_cairo/
About the high CPU usage:
Do you have proper hardware accelerated drivers installed for X?
I finally forced to use maximally 25 fps, by using a lock flag.
bool lock = 0;
bool needs_redraw = 0;
void Redraw(){
if(lock){
needs_redraw = 1;
return;
}
//draw image to a surface
needs_redraw = 0;
lock = 1;
Glib::signal_timeout().connect(Unlock, 20);
queue_draw();
}
bool Unlock(){
lock = 0;
if(needs_redraw) Redraw();
return false;
}
void on_expose_event(something){
//copy image from surface to widget's context
}
This is a sample code, but that's the idea. It will disallow redraw to be done more often then once per 20 ms.
I subclassed QGraphicsItem and reimplemented paint.
In paint I wrote something like this for labeling the item:
painter->drawText("Test",10,40);
After some time I think It may be useful to handle labeling with seperate item. So I wrote something like this.
QGraphicsTextItem *label = new QGraphicsTextItem("TEST",this);
setPos(10,40);
But two "TEST" drawing do not appear in the same place on screen. I guess difference may be related with item coordinates - scene coordinates. I tried all mapFrom... and mapTo... combinations inside QGraphicsItem interface but no progress. I want to drawings to appear in the same place on screen.
What I miss?
I assume that you are using the same font size and type in both cases. If the difference in position is very small the reason can be the QGraphicTextItem is using some padding for the text it contains. I would try to use QGraphicsSimpleTextItem that is not going to add fancy stuff internally and see if you still have the same problem. The coordinates system is the same one if you use painter or setPost so that is not the problem. If this doesn't help I will suggest to specify the same rect for both to avoid Qt adding it owns separation spaces.