Flickering when drawing the background outside of the main loop - c++

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.

Related

Moving Sprite (SFML) in c++ using Loops

I am new to c++ and as well as SFML. I am trying to make my sprite object move down in position relative to its last position using a loop. I am looking for the animation of it sprite object falling when the program starts.
I thought implementing a the sleep function in my for loop would help solve the issue i was having where the program would just display the object at the last iteration of the loop. However my program just freezes and crashes.
Looking for some direction. Maybe the sleep function isn't the right thing to call here?
#include <SFML/Graphics.hpp>
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
// Create the window here. Calling out the dimensions
sf::RenderWindow window(sf::VideoMode(800, 600), "Example Window");
// run the program as long as the window is open
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
//close window we requested
if (event.type == sf::Event::Closed)
{
window.close();
}
}
window.clear(sf::Color::Black);
sf::Texture texture;
if (!texture.loadFromFile("c:\\abstract.png"))
{
cout<<"Failed to load image...";
}
sf::Sprite sprite;
sprite.setTexture(texture);
sprite.setTextureRect(sf::IntRect(20,20,30,30));
for (float i = 0; i < 30.; i++)
{
sprite.move(sf::Vector2f(5.f, i));
window.draw(sprite);
Sleep(50);
}
window.display();
}
return 0;
}
What you are doing in your for is : Processing, drawing, processing, drawing... And finally displaying what you've drawn using window.display().
Meaning that what will be displayed on your window every frames, is the result of your "Processing, drawing" thing, in other word, 30 times your sprite at different positions.
What you want is to move your sprite a bit every frames. Thus, you have to finish your current while (window.isOpen()) iteration to move your sprite, draw it, and display it, and this over and over.
What you should do is declaring your sprite outside of your game loop (Which is while (window.isOpen())), and move it in this loop.
Step by step, your program should look like:
[Start]
Initialize your context
Create a sprite
Start looping
Clear the screen
Collect inputs
Move your sprite
Draw your sprite
Display your drawing on the window
End looping
[Exit]
The last thing you will need to handle is deltaTime (The timestep). Because if you move your sprite from (x,y) every frames, it means that the faster your computer is (Able to render a lot of frames quickly), the faster your sprite will move. In order to fix this problem, you'll have to move your sprite considering the time elapsed between the current frame and the previous frame (The slower is your PC, the more your sprite will move in one frame, the faster is your PC, the less your sprite will move in one frame). Timestep will cause your sprite to move (x,y) per second instead of (x,y) per frame, which is what you want in most graphic applications.

SDL2 "skip" frames when mouse no moving

I'm trying to make some animation with SDL2.
SDL2 has some bad performance, and my simple chess game was running at 10fps.
I don't want to redraw the whole screen every frames, it takes way to long. So in order to optimize my game I decided to code an Animation class ( a simple fade in/out effect) which only redraw some part of the screen everyframe (basicly redraw the selected piece)
void myGame::sdlLoop() {
SDL_Event events;
bool quit = false;
while (!quit) {
bool redraw = false; //We assume we don't want to redraw everything (yet)
while (SDL_PollEvent(&events)) {
switch (events.key.keysym.scancode) {
....
}
if(redraw) draw(); // Only redraw whole screen IF NEEDED
else drawAnimations(); // Better use that for better performance
}
}
}
void myGame::drawAnimations(){
int i = 0;
while(i < arr.size()){
....
drawThingsAtCertainsPixels(now_time, animation_start_time, animation_duration); //Basicly a simple fade effect, something like
//pixelColor = color1 * advancement + color2 * (1 - advancement)
}
// Show the window
SDL_RenderPresent( m_renderer );
}
So far so good, but I noticed a weird behavior.
The animation is "jerky", most of the frames are skipped
I ended up avec all of my fadeout unfinished because the last frame where skipped.
But, when I constantly move the mouse, everything goes right and no frame are dropped
I think it is linked to SDL wanting to optimize performance, and only run at 100% speed when someting important is going on (user inputting things or windows interacted).
Do you know why is this happening, and how to fix that ?
I mean how to have SDL2 computing every frame even if I don't move the mouse.
I feel a bit guilty for finding the solution right after posting this question (but I swear I tore my hair out a lot)
The solution is quite simple
while (!quit) {
bool redraw = false; //We assume we don't want to redraw everything (yet)
while (SDL_PollEvent(&events)) {
switch (events.key.keysym.scancode) {
....
}
if(redraw) draw(); // Only redraw whole screen IF NEEDED
else drawAnimation(); // Better use that for better performance
}
}
Just move the drawAnimations() function a bit lower, out of the while (SDL_PollEvent(&events)) {
while (!quit) {
bool redraw = false; //We assume we don't want to redraw everything (yet)
while (SDL_PollEvent(&events)) {
switch (events.key.keysym.scancode) {
....
}
}
if(redraw) draw(); // Only redraw whole screen IF NEEDED
else drawAnimation(); // Better use that for better performance
}

SDL and c++ -- More efficient way of leaving a trail behind the player?

so i'm fairly new with SDL, and i'm trying to make a little snowboarding game. When the player is moving down the hill, I want to leave a trail of off-coloured snow behind him. Currently, the way i have this working is I have an array (with 1000 elements) that stores the players last position. Then each frame, I have a for loop that loops 1000 times, to draw out the trail texture in all these last 1000 positions of the player...
I feel this is extremely inefficient, and i'm looking for some better alternatives!
The Code:
void Player::draw()
{
if (posIndex >= 1000)
{
posIndex = 0;
}
for (int i = 0; i < 1000; i++) // Loop through all the 1000 past positions of the player
{
// pastPlayerPos is an array of SDL_Rects that stores the players last 1000 positions
// This line calculates teh location to draw the trail texture
SDL_Rect trailRect = {pastPlayerPos[i].x, pastPlayerPos[i].y, 32, 8};
// This draws the trail texture
SDL_RenderCopy(Renderer, Images[IMAGE_TRAIL], NULL, &trailRect);
}
// This draws the player
SDL_Rect drawRect = {(int)x, (int)y, 32, 32};
SDL_RenderCopy(Renderer, Images[0], NULL, &drawRect);
// This is storing the past position
SDL_Rect tempRect = {x, y, 0, 0};
pastPlayerPos[posIndex] = tempRect;
posIndex++; // This is to cycle through the array to store the new position
This is the result, which is exactly what i'm trying to accomplish, but i'm just looking for a more efficient way. If there isn't one, i will stick with this.
There are multiple solutions. I'll give you two.
1.
Create screen-size surface. Fill it with alpha. On each player move, draw it's current position into this surface - so each movement will add you extra data to this would-be mask. Then blit this surface on screen (beware of blit order). In your case it could be improved by disabling alpha and initially filling surface with white, and blitting it first, before anything else. With that approach you can skip screen clearing after flip, by the way.
I recommend starting with this one.
2.
Not easy one, but may be more efficient (it depends). Save array points where player actually changed movement direction. After it, you need to draw chainline between these points. There is however no builtin functions in SDL to draw lines; maybe there are in SDL_gfx, i never tried it. This approach may be better if you'll use OpenGL backend later on; with SDL (or any other ordinary 2D drawing library), it's not too useful.

Clearing screen at key press in GLUT, c++

I have a program that monitors a text file for changes, and upon detecting one, the user has the option to redisplay the screen based on the contents of this text file. My problem is that when a new screen is requested, the contents of the previous screen stay, while the new contents overlaps it. I want the screen to be cleared before new data is put on the screen.
here is what I have:
void keyboard(unsigned char key, int x, int y){
if(key == 'c'){
c_pressed++;
cout<<"c pressed: "<<c_pressed<<"sound.txt cleared..."<<endl;
clear_file();
}
if(key=='v'){
v_pressed++;
cout<<"v pressed: "<<v_pressed<<"displaying new configuration..."<<endl;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glutPostRedisplay();
}
}
When the key 'c' is pressed, the text file is cleared. I have verified this works properly. Then after a separate program loads in new data into the text file, the user presses 'v' to load these new instructions. I've tried placing the clear function within the 'v' statement, and as well as in the display function...
void display(void){
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
read_in_sound();
cout<<"Number of sound events: "<<numLines<<endl;
for(int j=0; j<numLines; j++){
if(data[0+j*4]==1){
circle(0,0,200,50);
}
if(data[1+j*4]==1){
circle(0,400,200,50);
}
if(data[2+j*4]==1){
circle(400,400,200,50);
}
if(data[3+j*4]==1){
circle(400,0,200,50);
}
}
glFlush();
glutSwapBuffers();
}
But when I call redisplay, both the old and new screens are displayed.
As a general rule you should do OpenGL drawing calls (and clearing the scene is a drawing call) only from the display function. If something in a OpenGL scene changes the canonical way is to redraw the whole thing. So in reaction to any event you change your programs state and issue a redraw, which will ultimately redraw the scene using OpenGL.
If the scene is very complex any you want to only update the scene with only opaque geometry (anything that requires blending mandates a full redraw) you should use store the scene color and depth buffer to textures and use them to start from a well defined state. Ideally you use a framebuffer object for this.
This may not be the best method in the world, but I added a rectangle object that is the size of the window that matches the black background that gets called up each time I want to "redraw". It saves time from having to write in a framebuffer like the previous answer suggested.

Need help in optimizing a drawing code ...

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).