I have this snippet of code
void Graphics::render_text(std::string bunch_of_text) {
sf::Text text;
text.setFont(font); // font is a sf::Font
text.setString(bunch_of_text);
text.setCharacterSize(text_size); // in pixels, not points!
text.setFillColor(text_color);
text.setStyle(text_style);
window.draw(text);
window.display();
}
And sometimes this text is really long, and the remainder of the text can't be seen because of bounds.
Is there an opportunity to make text perfectly fitting on the screen, such as splitting text into multiple parts or making a new line(\n) inside the text where needed?
Here's one idea (pseudocode):
While text.getLocalBounds().width > window.size().x:
Determine an appropriate place in the text to add a newline. Possibly use text.getCharacterSize() and/or text.getLetterSpacing() to do this calculation.
text.setString() to set the new string.
Related
Here's my CODE:
#include <SFML\Graphics.hpp>
sf::RenderWindow renderWindow(sf::VideoMode(300, 300), "The Problem");
int main()
{
sf::Texture tX;
tX.loadFromFile("Recursos/Fondo.png");
sf::Sprite tXt(tX);
renderWindow.draw(tXt);
while (true) // main loop
{
renderWindow.display();
}
}
tX is a large sprite (think: background), so I want to avoid redrawing it every frame.
When I try this, I get flickering, and I have no idea where it's coming from.
Your code, simplified, pseudo:
Initialize();
Draw();
Loop {
Display();
}
What you're doing is drawing the scene to a buffer (without clearing it first, by the way), and then displaying it in a loop (without redrawing anything).
I think the reason you have flickering is due to double-buffering (v-sync).
What ends up happening is that you drew to one buffer, but left the other one empty. When you display the active buffer, they get flipped (so the next time you display, it's an empty buffer).
You really should draw inside the loop.
Alternatively, you can disable multiple-buffering, or try drawing, displaying, drawing again, and then looping (so that you draw to both buffers, assuming there are only two).
Both solutions are not elegant.
If drawing the background really needs optimization, I'm afraid SFML won't give you that granularity. You might want to look in to OpemGL Stencil wizardry.
I draw some text to a surface (using SDL_ttf) and then I want to change the text on the surface. If I just redraw the surface the text does not go away. I have looked at several forum posts on how to fix the problem but I just cannot seem to figure it out. In particular I cannot understand why this solution does not work: (code is long so this just gives the essentials)
In Class file declared:
SDL_Surface* box; // These two are initialised to the
SDL_Surface* boxCopy; // same image
At the start of my render function:
*box = *boxCopy; \\Reset box surface
My understanding of pointers and C++ (which is admittedly limited) suggests that this should make the surface pointed at by box equal to the surface pointed at by boxCopy. Instead the boxCopy surface becomes a copy of box. I have no idea how boxCopy can be changed by this line of code but it seems like that is what is happening.
I'm not sure i completely understand your problem but hopefully this can help.. It's easier to update the text whenever the surface it's drawn on is to be updated rather than updating it whenever the actual text is updated. It might not be as optimized performance wise but i would say it's easier in most cases.
A typical program loop would include a re-rendering of a surface representing the screen followed by an SDL_Flip of this surface. You can of course optimize your re-rendering so you only render what has actually been updated since last frame. Is that what you're working on perhaps? If so, and if you use the method below you should be aware that the new text only covers the size of the new text and not the entire old text. I usually solve this by first drawing a filled rectangle and then the new text.
Here is a TTF example showing how text can be drawn on a surface (here called m_Screen, which is the surface flipped to screen every frame) in the simple case where i have one background color only:
void drawText(const char* string, int x, int y,
int fR, int fG, int fB, int bR, int bG, int bB)
{
SDL_Color foregroundColor = { fR, fG, fB };
SDL_Color backgroundColor = { bR, bG, bB };
SDL_Surface* textSurface = TTF_RenderText_Shaded(m_Font, string,
foregroundColor,
backgroundColor);
SDL_Rect textLocation = { x, y, 0, 0 };
SDL_BlitSurface(textSurface, NULL, m_Screen, &textLocation);
SDL_FreeSurface(textSurface);
}
Notice that this has been done before calling drawText (with some suitable font size):
m_Font = TTF_OpenFont("arial.ttf", size);
And this is done at cleanup:
TTF_CloseFont(m_Font);
I was wondering how i get the dimensions of my text in SFML?
I tried to do it like this:
sf::Text text("Hello SFML", font, 50);
// using text.getRect()
// i also tried getScale() & getSize()
// neither are correct
text.setPosition( window.getSize().y/2 - text.getRect().y,50 );
Does any one know ?
Thanks :)
Looking at the documentation it seems like the function
getLocalBounds could be of use to you. The line would be:
float width = text.getLocalBounds().width;
I'm not sure if the sf::Text object would add any padding on the ends of the bounding rectangle.
Alternatively, you could make use of findCharacterPos with something like:
float width = text.findCharacterPos(numChars - 1).x - text.findCharacterPos(0).x;
where numChars is the number of characters in the string of your text object. However, since findCharacterPos will return global coordinates, it's probably more convenient to use getLocalBounds, this way you don't have to worry about whether your text object has any transformations applied to it.
You can use getGlobalBounds() to get the size/coordinates after a transformation (rotation, scale, move...).
Otherwise it's getLocalBounds().
Doc: http://www.sfml-dev.org/documentation/2.3.1/classsf_1_1Text.php
We just started learning windows programming in C++. We have to make a program that has 4 die on the screen, and when the user presses 'SpaceBar', the die roll, or the number of dots on the die change randomly. Our professor hasent given us a lot of information, so I am kind of just looking for some direction.
Right now, I have 4 squares drawn on the screen, made with the Rectangle() function.
Rectangle(hDC,30,100,130,200);
Rectangle(hDC,180,100,280,200);
Rectangle(hDC,330,100,430,200);
Rectangle(hDC,480,100,580,200);
My question is 1) how would I go about drawing dots on these 'squares' and not on the 'screen'. So if I move the die upwards, the dots move with the square and dont just stay stationed painted on the screen. And 2.) How would I go about making those dots randomly change when spacebar is pressed (simulating that they have been rolled)?
Just looking for some direction, thanks.
1)
You will still have to draw them on the screen, but you can structure your program to realize the dots as part of the square.
void moveSquare()
{
//change square position
//change dots positions the same as you changed the square
}
2)
You can capture keypresses in your window with the WM_KEYDOWN and WM_KEYUP messages, or the WM_CHAR message. Just start a chain of changing how many dots are supposed to appear on the die when space is pressed (SetTimer could be handy), and let WM_PAINT do the work of painting the dots (or call something to calculate the positions of the dots, and let WM_PAINT loop through each dot it needs to draw.
void OnSpacePressed()
{
//start changing dots every so often, handled elsewhere
//maybe check if finished rolling before doing so
}
void calculateDotPositions()
{
switch (numberOfDots) {...} //hint: use the square as a reference point
}
void OnPaint()
{
//paint each sqaure
//paint each dot in the correct position, which should be updated with square
}
void OnChangeDots()
{
//change number of dots
//also start a new change to happen later if not done rolling
}
For drawing dots, use Warren P's reference link.
Another method is to create a bitmap or picture in memory. One for each of the 6 faces of the die. The objective here is to copy the bitmaps to the screen, rather than having to redraw them each time. Research "bitmap", and "bitblt".
You should make a routine that draws a die at the origin, offset by given coordinates. I'm not familiar with the particular library you are using, so I don't know what hDC is, but it should look something like the following.
void drawDie(HDC hDC, int xCoord, int yCoord, int dieValue)
{
Rectangle(hDC, -50 + xCoord, -50 + yCoord, 50 + xCoord, 50 + yCoord);
// draw some number of circles specified by dieValue at appropriate coordinates
// translated by xCoord and yCoord arguments
}
Then you can just redraw dice over your previous ones if you want them to change.
I needed some help in trying to optimize this code portion ... Basically here's the thing .. I'm making this 'calligraphy pen' which gives the calligraphy effect by simply drawing a lot of adjacent slanted lines ... The problem is this: When I update the draw region using update() after every single draw of a slanted line, the output is correct, in the sense that updates are done in a timely manner, so that everything 'drawn' using the pen is immediately 'seen' the drawing.. however, because a lot (100s of them) of updates are done, the program slows down a little when run on the N900 ...
When I try to do a little optimization by running update after drawing all the slanted lines (so that all lines are updated onto the drawing board through a single update() ), the output is ... odd .... That is, immediately after drawing the lines, they lines seem broken (they have vacant patches where the drawing should have happened as well) ... however, if I trigger a redrawing of the form window (say, by changing the size of the form), the broken patches are immediately fixed !! When I run this program on my N900, it gets the initial broken output and stays like that, since I don't know how to enforce a redraw in this case ...
Here is the first 'optimized' code and output (partially correct/incorrect)
void Canvas::drawLineTo(const QPoint &endPoint)
{
QPainter painter(&image);
painter.setPen(QPen(Qt::black,1,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
int fx=0,fy=0,k=0;
qPoints.clear();
connectingPointsCalculator2(qPoints,lastPoint.x(),lastPoint.y(),endPoint.x(),endPoint.y());
int i=0;
int x,y;
for(i=0;i<qPoints.size();i++)
{
x=qPoints.at(i).x();
y=qPoints.at(i).y();
painter.setPen(Qt::black);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
}
**//Updating only once after many draws:**
update (QRect(QPoint(lastPoint.x()-5,lastPoint.y()-5), QPoint(endPoint.x()+5,endPoint.y()+5)).normalized());
modified = true;
lastPoint = endPoint;
}
Image right after scribbling on screen:
http://img823.imageshack.us/img823/8755/59943912.png
After re-adjusting the window size, all the broken links above are fixed like they should be ..
Here is the second un-optimized code (its output is correct right after drawing, just like in the second picture above):
void Canvas::drawLineTo(const QPoint &endPoint)
{
QPainter painter(&image);
painter.setPen(QPen(Qt::black,1,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin));
int fx=0,fy=0,k=0;
qPoints.clear();
connectingPointsCalculator2(qPoints,lastPoint.x(),lastPoint.y(),endPoint.x(),endPoint.y());
int i=0;
int x,y;
for(i=0;i<qPoints.size();i++)
{
x=qPoints.at(i).x();
y=qPoints.at(i).y();
painter.setPen(Qt::black);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
**//Updating repeatedly during the for loop:**
update(QRect(QPoint(x-5,y-5), QPoint(x+5,y+5)).normalized());//.adjusted(-rad,-rad,rad,rad));
}
modified = true;
int rad = (myPenWidth / 2) + 2;
lastPoint = endPoint;
}
Can anyone see what the issue might be ?
Sorry if I misunderstood, but have you tried to use the "double buffer" approach? Instead of drawing directly on the screen, you "draw" your points and lines to a memory buffer. After that, you just copy the buffer to the screen. This is faster and avoids flickering.
As I understand you should find min and max of x and y processed in your for-loop and use them in update(QRect(QPoint(minX-5, minY-5), QPoint(maxX+5, maxY+5)).normalized());
I'm not sure exactly what your issue is with the broken lines, but I can offer you this advice: keep your pen around. Instead of this:
for(i=0;i<qPoints.size();i++)
{
// ...
painter.setPen(Qt::black);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
// ...
}
do this:
QPen black_pen(Qt::black);
for(i=0;i<qPoints.size();i++)
{
// ...
painter.setPen(black_pen);
painter.drawLine(x-5,y-5,x+5,y+5); **// Drawing slanted lines**
// ...
}
Even more, if you are repeatedly calling your drawLineTo function with the same pen every time, store the pen in your class and keep it around. At my company, we've found that to vastly reduce drawing times where we can take advantage of it. (One instance on a large image cut drawing times in half.)
One other note: I'm not sure what type the image you are painting is, but I'm assuming it is a QImage. When you are done drawing, if you will be using the unmodified image repeatedly, you might convert it once to a QPixmap. The QPixmap class is stored in a way that is supposed to be ready for blitting directly to the screen (but it a lot slower to modify in many cases, because of that).