SFML community forums
Help => Graphics => Topic started by: pirate42 on January 15, 2012, 01:59:20 pm
-
Some sprites do not appear ... but, instead, you will see some random image who come from (i think) the cache of the GPU...
But in others computer, HP EliteBook with windows 7, it's working fine.
Does the trouble come from our Mac ?
Mac Specifications:
MacBook Pro - 17 pouces, mi-2010
2,66 GHz Intel Core i7
8 Go 1067 MHz DDR3
NVIDIA GeForce GT 330M 512 MB
Mac OS X Lion 10.7.2 (11C74)
Here are a screenshot of the troubles :
(http://img6.imageshack.us/img6/9776/capturedcran20120114195.png) (http://imageshack.us/photo/my-images/6/capturedcran20120114195.png/)
here are the code :
void DisplaySfml::loadImage(std::string const &name, std::string const & pathImage)
{
sf::RenderTexture *renderTexture = new sf::RenderTexture;
sf::Texture texture;
if (!(texture.LoadFromFile(pathImage)))
std::cerr << "Image [" << pathImage << "] is missing" << std::endl;
sf::Sprite spriteTmp(texture);
spriteTmp.Scale(Width_ / 1920.f, Height_ / 1200.f);
if (!renderTexture->Create(texture.GetWidth() * (Width_ / 1920.f),
texture.GetHeight() * (Height_ / 1200.f)))
std::cerr << "RenderTexture [" << pathImage << "] failed to create" << std::endl;
renderTexture->Clear(sf::Color::Transparent);
renderTexture->Draw(spriteTmp);
renderTexture->Display();
displayImage_[name].sprite_ = new sf::Sprite(renderTexture->GetTexture());
displayImage_[name].width_ = renderTexture->GetWidth();
displayImage_[name].height_ = renderTexture->GetHeight();
displayImage_[name].loop_ = 0;
displayImage_[name].screenWidth_ = 0;
saveTexture_.push_back(renderTexture);
}
In advance, thanks a lot for your help ;)
-
We'd probably need a minimal and complete sample code to reproduce your issue.
-
We'd probably need a minimal and complete sample code to reproduce your issue.
Sent by pm ;)
Thanks ;)
-
Well.. I didn't say I'd be the one to find what's wrong here. It's just so that if someone has an idea, he/she can answer here. You should post your minimal and complete code here, not in a pm.
-
here is the code >> next post ;)
-
Please post a minimal and complete code directly in the forum (no download site). Reduce your actual code to a few lines, so that the problem is still reproducable.
-
Here is the MINIMAL code:
main.cpp
#include "DisplaySfml.hh"
#define WIDTH (desktop.width())
#define HEIGHT (desktop.height())
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDesktopWidget desktop;
IDisplay* Win = new DisplaySfml();
Win->InitWindow(WIDTH, HEIGHT, "Air Type");
// Win->loadImage("Ship", "./Resources/ShipNormal.png");
// Win->loadImage("ShipForward", "./Resources/ShipForward.png");
// Win->loadImage("ShipBack", "./Resources/ShipBack.png");
// Win->loadImage("ShipLeft", "./Resources/ShipLeft.png");
// Win->loadImage("ShipRight", "./Resources/ShipRight.png");
Win->loadImage("Background", "./Resources/Background.jpg");
// Win->loadImage("FrontStars", "./Resources/FrontStars.png");
// Win->loadImage("BackStars", "./Resources/BackStars.png");
// Win->loadImage("DoubleStars", "./Resources/FrontStars.png");
// Win->getSprite("Ship")->SetPosition(WIDTH / 2, HEIGHT / 2);
Win->DisplayWindow();
return EXIT_SUCCESS;
}
DisplaySfml.cpp
#include "DisplaySfml.hh"
DisplaySfml::DisplaySfml()
:Speed_(0.01f)
{
turnSendDirection_[sf::Keyboard::Down] = &moveRight;
turnSendDirection_[sf::Keyboard::Up] = &moveLeft;
turnSendDirection_[sf::Keyboard::Left] = &moveBack;
turnSendDirection_[sf::Keyboard::Right] = &moveForward;
turnSendDirection_[sf::Keyboard::Space] = &moveSpace;
}
DisplaySfml::~DisplaySfml()
{
for (std::vector<sf::RenderTexture*>::iterator it = saveTexture_.begin(); it != saveTexture_.end(); ++it)
delete *it;
for (std::map<std::string, Sprite>::iterator it = displayImage_.begin(); it != displayImage_.end(); ++it)
delete (it->second).sprite_;
delete Window_;
}
void DisplaySfml::InitWindow(int Width, int Height, const std::string & Title)
{
Width_ = Width;
Height_ = Height;
Window_ = new sf::RenderWindow(sf::VideoMode(Width_, Height_), Title.c_str(), sf::Style::None);
Window_->EnableVerticalSync(true);
}
void DisplaySfml::loadImage(std::string const &name, std::string const & pathImage)
{
sf::RenderTexture *renderTexture = new sf::RenderTexture;
sf::Texture texture;
if (!(texture.LoadFromFile(pathImage)))
std::cerr << "Image [" << pathImage << "] is missing" << std::endl;
sf::Sprite spriteTmp(texture);
spriteTmp.Scale(Width_ / 1920.f, Height_ / 1200.f);
if (!renderTexture->Create(texture.GetWidth() * (Width_ / 1920.f), texture.GetHeight() * (Height_ / 1200.f)))
std::cerr << "RenderTexture [" << pathImage << "] failed to create" << std::endl;
renderTexture->Clear(sf::Color::Transparent);
renderTexture->Draw(spriteTmp);
renderTexture->Display();
displayImage_[name].sprite_ = new sf::Sprite(renderTexture->GetTexture());
displayImage_[name].width_ = renderTexture->GetWidth();
displayImage_[name].height_ = renderTexture->GetHeight();
displayImage_[name].loop_ = 0;
displayImage_[name].screenWidth_ = 0;
saveTexture_.push_back(renderTexture);
}
sf::Sprite *DisplaySfml::getSprite(std::string const &name)
{
return displayImage_[name].sprite_;
}
int DisplaySfml::getXSprite(std::string const &name)
{
return displayImage_[name].sprite_->GetPosition().x;
}
int DisplaySfml::getYSprite(std::string const &name)
{
return displayImage_[name].sprite_->GetPosition().y;
}
void DisplaySfml::drawImage(std::string const &name, int const &x, int const &y)
{
displayImage_[name].sprite_->SetPosition(x, y);
Window_->Draw(*(displayImage_[name].sprite_));
}
void DisplaySfml::DisplayWindow()
{
x = 0;
y = 0;
Clock_.Reset();
Window_->SetFramerateLimit(60);
while (Window_->IsOpen())
{
event();
ElapsedTime_ = Clock_.GetElapsedTime();
if (ElapsedTime_ > 17)
{
Window_->Clear();
drawImage("Background", 0, 0);
// loopSprite("Background", 3);
// loopSprite("FrontStars", 2);
// loopSprite("BackStars", 1);
// drawImage("Ship", getXSprite("Ship") + x, getYSprite("Ship") + y);
// drawImage("Ship", 500, 500);
// loopSprite("DoubleStars", 6);
Window_->Display();
Clock_.Reset();
}
}
}
void DisplaySfml::event()
{
sf::Event event;
while (Window_->PollEvent(event))
{
if (event.Type == sf::Event::KeyPressed)
{
if ((event.Key.Code == sf::Keyboard::Escape))
{
Window_->Close();
break;
}
for (std::map<sf::Keyboard::Key, setNewPos>::iterator it = turnSendDirection_.begin(); it != turnSendDirection_.end(); ++it)
{
if (sf::Keyboard::IsKeyPressed(it->first))
turnSendDirection_[it->first](x, y);
}
}
}
}
void DisplaySfml::loopSprite(const std::string name, int const speed)
{
if ((displayImage_[name]).screenWidth_ >= Width_)
(displayImage_[name]).screenWidth_ = 0;
if ((displayImage_[name]).loop_ >= (displayImage_[name]).width_)
(displayImage_[name]).loop_ = 0;
sf::IntRect leftRect((displayImage_[name]).loop_, 0,
Width_ - (displayImage_[name]).screenWidth_, Height_);
(displayImage_[name]).sprite_->SetTextureRect(leftRect);
drawImage(name, 0, 0);
if ((displayImage_[name]).loop_ + Width_ >= (displayImage_[name]).width_)
{
sf::IntRect rightRect(0 ,0, (displayImage_[name]).screenWidth_, Height_);
(displayImage_[name]).sprite_->SetTextureRect(rightRect);
drawImage(name, Width_ - (displayImage_[name]).screenWidth_, 0);
(displayImage_[name]).screenWidth_ += speed;
}
(displayImage_[name]).loop_ += speed;
}
Any help ?
-
Here is the MINIMAL code:
The code is neither minimal nor complete, even though this has been told you three times.
What we need is a short code with only a main() function that we can directly compile and test. Debugging gets very tedious if we first must become acquainted to your project-specific code. Remove everything that's unnecessary and not directly related to your problem, including dependencies to other libraries like Qt.
I know this implies some work, but otherwise we have to do it, who need even more time because we're not familiar with your code.
-
Sorry for the misunderstood :(
here is a minimal code, as requested :
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <SFML/System.hpp>
int main()
{
// Adjust these two variables to your screen resolution
int Width_ = 1680;
int Height_ = 1050;
float ElapsedTime_;
// Creating the sf::RenderWindow
sf::RenderWindow *Window_ = new sf::RenderWindow(sf::VideoMode(Width_, Height_), "Title", sf::Style::Fullscreen);
sf::Clock Clock_;
sf::Texture texture;
// Loading an image in a sf::Texture
if (!(texture.LoadFromFile("./image.png")))
return -1;
// Creating the sf::Sprite from the texture, and scaling it
sf::Sprite spriteTmp(texture);
spriteTmp.Scale(Width_ / 1920.f, Height_ / 1200.f);
// Creating the sf::RenderTexture, and filling it with the scaled sprite
sf::RenderTexture *renderTexture = new sf::RenderTexture;
if (!renderTexture->Create(texture.GetWidth() * (Width_ / 1920.f), texture.GetHeight() * (Height_ / 1200.f)))
return -1;
renderTexture->Clear(sf::Color::Transparent);
renderTexture->Draw(spriteTmp);
renderTexture->Display();
// Creating the new sf::sprite with the new scaled texture
sf::Sprite *sprite = new sf::Sprite(renderTexture->GetTexture());
while (Window_->IsOpen())
{
// event
ElapsedTime_ = Clock_.GetElapsedTime();
if (ElapsedTime_ > 17)
{
Window_->Clear();
Window_->Draw(*sprite);
Window_->Display();
Clock_.Reset();
}
else
sf::Sleep(2);
}
}
here is the compilation line :
g++ main.cpp -lsfml-graphics -lsfml-system -lsfml-window
I know that i can use a sf::Texture instead of sf::RenderTexture, but, somewhere in my program, i need a new texture already scaled.
Please, refer to the screenshot i posted before.
sometimes, the full texture is showing good, but it often load some random pixels
by the way, I tried on 2 macbook pro with different graphic cards
thx a lot for your time
-
Can you try to:
- remove the custom time handling, just render everything at full speed
- add an event loop
-
ok
I tried this, but its still not working :(
while (Window_->IsOpen())
{
sf::Event event;
while (Window_->PollEvent(event))
{
if (event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Keyboard::Escape)
{
Window_->Close();
break;
}
}
Window_->Clear();
Window_->Draw(*sprite);
Window_->Display();
}
-
I also tried different file format, it doesn't work
any idea ?
thanks
-
by the way, I tried on 2 macbook pro with different graphic cards
And it works? Or not?
Have you tried on PCs (Linux or Windows)?
-
by the way, I tried on 2 macbook pro with different graphic cards
And it works? Or not?
Have you tried on PCs (Linux or Windows)?
no it doesnt work on mac computers
it works on windows (pc) computer and also on ubuntu virtual machine under mac os
-
There's definitely a issue here. I modified a little bit the code sample from the Xcode templates like this :
#include <SFML/Graphics.hpp>
#include "ResourcePath.hpp"
int main (int argc, const char * argv[])
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
// Load a sprite to display
sf::Texture texture;
if (!texture.LoadFromFile(ResourcePath() + "cute_image.jpg"))
return EXIT_FAILURE;
sf::Sprite spriteTmp(texture);
sf::RenderTexture rt;
if (!rt.Create(texture.GetWidth(), texture.GetHeight()))
return EXIT_FAILURE;
// Create RT with some content. DOESN'T works here.
/*
rt.Clear();
rt.Draw(spriteTmp);
rt.Display();
sf::Sprite sprite(rt.GetTexture());
//*/
// Start the game loop
while (window.IsOpen())
{
// Process events
sf::Event event;
while (window.PollEvent(event))
{
// Close window : exit
if (event.Type == sf::Event::Closed)
window.Close();
// Escape pressed : exit
if (event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Keyboard::Escape)
window.Close();
}
// Create RT with some content. Works here after the second round of the loop.
//*
rt.Clear();
rt.Draw(spriteTmp);
rt.Display();
sf::Sprite sprite(rt.GetTexture());
//*/
// Draw the sprite
window.Draw(sprite);
// Update the window
window.Display();
}
return EXIT_SUCCESS;
}
It appears that the RT's content must be drawn/displayed several times (in fact, 2 times) in the main loop to render as expected. If the RT's content is drawn before the main loop then some artefacts appear.
However I have no clue why this is happening! :?
An archive can be downloaded here (https://legacy.sfmluploads.org/file/101) with all the material to test this issue.
-
thanks for your time.
the problem is, I load all my images before the main loop, so I cannot draw the RT twice :?
is there a temporary solution ?
-
hello,
tested again on another windows computer and it works
any idea ?
-
Since it's a Mac OS X only bug, I cannot help. We'd need someone with a Mac and OpenGL/debugging skills.
-
I noticed you clear your rendertexture using sf::Color::Transparent. Try clearing it with a solid color or without arguments
-
I noticed you clear your rendertexture using sf::Color::Transparent. Try clearing it with a solid color or without arguments
unfortunately, this is worse. I get no transparency, and I have more artifacts.
Since it's a Mac OS X only bug, I cannot help. We'd need someone with a Mac and OpenGL/debugging skills.
thx by the way
-
is there a temporary solution ?
I just tested some more things and it came out that the following code will work (except the window will "flash" when it is displayed the first time).
#include <SFML/Graphics.hpp>
#include "ResourcePath.hpp"
int main (int argc, const char * argv[])
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
// Load a sprite to display
sf::Texture texture;
if (!texture.LoadFromFile(ResourcePath() + "cute_image.jpg"))
return EXIT_FAILURE;
sf::Sprite spriteTmp(texture);
sf::RenderTexture rt;
if (!rt.Create(texture.GetWidth(), texture.GetHeight()))
return EXIT_FAILURE;
// Create RT with some content.
window.Display(); // MAKES THINGS WORK!
rt.Clear();
rt.Draw(spriteTmp);
rt.Display();
sf::Sprite sprite(rt.GetTexture());
// Start the game loop
while (window.IsOpen())
{
// Process events
sf::Event event;
while (window.PollEvent(event))
{
// Close window : exit
if (event.Type == sf::Event::Closed)
window.Close();
// Escape pressed : exit
if (event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Keyboard::Escape)
window.Close();
}
// Draw the sprite
window.Draw(sprite);
// Update the window
window.Display();
}
return EXIT_SUCCESS;
}
Adding "window.Display();" before "rt.Clear();" makes it works. Still no idea why. Will spend some time on this issue ASAP (but exams first!).
-
Can you try to add calls to glFlush() after or before drawing to the render-texture?
-
It doesn't help. I tried glFlush between each possible line but no luck. =/
-
Adding "window.Display();" before "rt.Clear();" makes it works. Still no idea why. Will spend some time on this issue ASAP (but exams first!).
Can you try to add calls to glFlush() after or before drawing to the render-texture?
first, both solution did not work in my program.
but then, I found a solution (for the moment, the bug did not appear again)
In my program (not in this sample code), I used "sf::RenderTexture*" instead of "sf::RenderTexture"
I changed it to "sf::RenderTexture"
Then, once render texture has been displayed, I create a new sf::texture(rt. GetTexture)
then I create a new sprite using the texture and with both solution, it works like a charm
but if I use a pointer for RenderTexture, it does not work and some artifacts appear
I guess that window.Display() calls glFlush() ?
I put the glFlush() before calling rt.Create()
so Hiura, your sample code should work with glflush if you create a new texture from rt, then create the sprite
by the way thanks a lot to both of you, I will post a message tomorrow after lots of test in order to tell you if problem is resolved or not
Bonne nuit et merci ;)
[/quote]
-
I forgot an important thing. It doesn't work with integrated graphic card
you have to use the other one (geforce GT 330m for me)
on mac by default, the system switches automatically between the 2 graphic cards
I used this software to select manually which one I want to use :
gfxCardStatus
-
I put the glFlush() before calling rt.Create()
That's right! I forget to try this one and it indeed seems to work.
Recap :
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include "ResourcePath.hpp"
int main (int argc, const char * argv[])
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
// Load a sprite to display
sf::Texture texture;
if (!texture.LoadFromFile(ResourcePath() + "cute_image.jpg"))
return EXIT_FAILURE;
sf::Sprite spriteTmp(texture);
glFlush(); // FIXIT
sf::RenderTexture rt;
if (!rt.Create(texture.GetWidth(), texture.GetHeight()))
return EXIT_FAILURE;
// Create RT with some content.
rt.Clear();
rt.Draw(spriteTmp);
rt.Display();
sf::Sprite sprite(rt.GetTexture());
// Start the game loop
while (window.IsOpen())
{
// Process events
sf::Event event;
while (window.PollEvent(event))
{
// Close window : exit
if (event.Type == sf::Event::Closed)
window.Close();
// Escape pressed : exit
if (event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Keyboard::Escape)
window.Close();
}
window.Clear();
// Draw the sprite
window.Draw(sprite);
// Update the window
window.Display();
}
return EXIT_SUCCESS;
}
I don't know if it is completely related or not, but I also tried something a little different with Image conversion. It appears that in the following code the two glFlush are required in order to prevent the same artefact bug.
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
// Load a sprite to display
sf::Texture texture;
if (!texture.LoadFromFile(ResourcePath() + "cute_image.jpg"))
return EXIT_FAILURE;
sf::Sprite spriteTmp(texture);
glFlush(); // FIXIT A
sf::RenderTexture rt;
if (!rt.Create(texture.GetWidth(), texture.GetHeight()))
return EXIT_FAILURE;
// Create RT with some content.
rt.Clear();
rt.Draw(spriteTmp);
rt.Display();
sf::Image i = rt.GetTexture().CopyToImage();
sf::Texture t;
t.LoadFromImage(i);
glFlush(); // FIXIT B
sf::Sprite sprite(t);
// Start the game loop
while (window.IsOpen())
:
:
Maybe it will help someone to understand this issue.
(I don't have any Intel graphics so I can't say anything about them.)
-
Thanks for the investigations :)
Each render-target has its own separate OpenGL context, but they share resources, such as textures, with each other. Another interesting fact is that OpenGL commands are never executed immediately, they are queued and flushed later (which you can force by calling glFlush).
So I guess that when the render-texture's context tries to draw the loaded texture, it's not ready yet in this context because there are still pending commands in the window's context. But I don't know why it happens only on OS X... I guess that other drivers are more clever :lol:
I'll see if I can flush contexts internally, when switching contexts, and if it doesn't impact performances too much.
-
I'll see if I can flush contexts internally, when switching contexts, and if it doesn't impact performances too much.
If the performances are too reduced maybe we can do it only on Mac, or, to be more precise : only on Mac until this issue appears on other OSes.
BTW, I tried on Nvidia GPU. It might work on ATI GPU (maybe) but I can't test that.
-
I'll see if I can flush contexts internally, when switching contexts, and if it doesn't impact performances too much.
If the performances are too reduced maybe we can do it only on Mac, or, to be more precise : only on Mac until this issue appears on other OSes.
BTW, I tried on Nvidia GPU. It might work on ATI GPU (maybe) but I can't test that.
someone in my group project has a mac with an ATI graphic card. I let you informed if it works.
But I don't know why it happens only on OS X... I guess that other drivers are more clever
yes, and the problem on mac is that you cannot choose your drivers ... so maybe in a future drivers update by apple, this issue will be solved
-
It's also working with ATI GPU :)
Thanks a lot for your help and hope that our troubles will help you to make your Librarie even better ;)