I have an issue with how things are rendering. When I delete a RenderTexture, the screen is never cleared, and nothing ever renders. I checked if RenderWindow::clear() is even called by outputting text after the method is called, and looks like it is. If I comment out the line that deletes the RenderTexture, everything works fine.
sf::Vertex * sh = new sf::Vertex[3];
sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));
sf::RenderTexture * shipRTex = new sf::RenderTexture; //A RenderTexture due to be deleted
if(!shipRTex->create(64,64)){
return -1;
}
shipRTex->draw(sh, 3, sf::Triangles);
shipRTex->setSmooth(false);
shipRTex->display();
sf::Texture shipTex; //This will replace the RenderTexture
if(!shipTex.create(64,64)){
return -1;
}
shipTex = shipRTex->getTexture(); //Replacing
sf::Sprite ship(shipTex);
ship.setColor(sf::Color(255,255,255,255));
ship.setOrigin(32, 32);
ship.setScale(1.f/8.f, 1.f/8.f);
ship.setPosition(window.getSize().x/2, window.getSize().y/2);
delete[] sh;
delete shipRTex; //Everything renders fine without this line
I checked to see if this was because RenderTexture::getTexture() only points to a texture, (which makes no sense because a copy is made to replace it, but I decided to try it anyway) so I tried deleting shipTex to see what would happen if the sprite no longer had something to render. A white square appeared, but it didn't cause the problems deleting shipRTex did. I wondered if it was because I had not called Texture::create(), but that didn't help. I finally ran out of ideas and I came here. Do you have any idea about what could be causing this?
Here is a complete example, which demonstrates the problem, with a whole lot of stuff taken out so as to avoid distracting from the focus of the problem. It's not quite as minimal as I would want it, but I wanted to keep the graphical stuff mostly the same.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
int main(){
sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);
sf::Vertex * sh = new sf::Vertex[3];
sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));
sf::RenderTexture * shipRTex = new sf::RenderTexture;
if(!shipRTex->create(64,64)){
return -1;
}
shipRTex->draw(sh, 3, sf::Triangles);
shipRTex->setSmooth(false);
shipRTex->display();
sf::Texture shipTex;
if(!shipTex.create(64,64)){
return -1;
}
shipTex = shipRTex->getTexture();
sf::Sprite ship(shipTex);
ship.setColor(sf::Color(255,255,255,255));
ship.setOrigin(32, 32);
ship.setScale(1.f/4.f, 1.f/4.f);
ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);
delete[] sh;
delete shipRTex; //That pesky line
window.setVerticalSyncEnabled(true);
window.setFramerateLimit(60);
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if(event.type == sf::Event::Closed){
window.close();
}
}
window.clear(sf::Color(127,63,31,255));
window.draw(ship);
window.display();
}
return 0;
}
How does a change in memory relate to the rendering of something on a window?
The window you see is just the representation of some memory in the GPU. A render texture is basically nothing else than a window that doesn't get draw to the screen, but is only kept in memory.
So when you look at the chain RenderTexture -> Texture -> Window you see the connection between. But it seems like on your GPU textures are handeled oddly and when you actually copy from the render texture into a normal texture, it somehow still links to the render texture. Now when you delete the render texture before drawing it to the screen, the copied texture seems to be also affected by the deletion and thus shows nothing.
What causes what? Is it direct?
Hard to say... It works for FRex on an Intel GPU and for me on an AMD GPU, so it really seems to be a problem with your PC or at least with the graphics card or its driver. (Is the driver up-to-date?)
What happens if you delete the render texture after the application execution? E.g.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
int main(){
sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);
sf::Vertex * sh = new sf::Vertex[3];
sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));
sf::RenderTexture * shipRTex = new sf::RenderTexture;
if(!shipRTex->create(64,64)){
return -1;
}
shipRTex->clear(sf::Color::Transparent);
shipRTex->draw(sh, 3, sf::Triangles);
shipRTex->setSmooth(false);
shipRTex->display();
sf::Texture shipTex;
if(!shipTex.create(64,64)){
return -1;
}
shipTex = shipRTex->getTexture();
sf::Sprite ship(shipTex);
ship.setColor(sf::Color(255,255,255,255));
ship.setOrigin(32, 32);
ship.setScale(1.f/4.f, 1.f/4.f);
ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);
window.setVerticalSyncEnabled(true);
window.setFramerateLimit(60);
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if(event.type == sf::Event::Closed){
window.close();
}
}
window.clear(sf::Color(127,63,31,255));
window.draw(ship);
window.display();
}
delete[] sh;
delete shipRTex; //That pesky line
return 0;
}
Note: The application will have a memory leak, if render texture fails to be created.
But as I said the dynamic allocation with new/delete is kind of depreciated in C++. If you don't have to create the render texture on the fly you could just create everything on the applications stack:
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
int main(){
sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);
sf::Vertex sh[3];
sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));
sf::RenderTexture shipRTex;
if(!shipRTex.create(64,64)){
return -1;
}
shipRTex->clear(sf::Color::Transparent);
shipRTex.draw(sh, 3, sf::Triangles);
shipRTex.setSmooth(false);
shipRTex.display();
sf::Texture shipTex;
if(!shipTex.create(64,64)){
return -1;
}
shipTex = shipRTex.getTexture();
sf::Sprite ship(shipTex);
ship.setColor(sf::Color(255,255,255,255));
ship.setOrigin(32, 32);
ship.setScale(1.f/4.f, 1.f/4.f);
ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);
window.setVerticalSyncEnabled(true);
window.setFramerateLimit(60);
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if(event.type == sf::Event::Closed){
window.close();
}
}
window.clear(sf::Color(127,63,31,255));
window.draw(ship);
window.display();
}
return 0;
}
Note: Since everything is on the stack, there won't be any memory issue.
Or if you really need dynamic memory, then you should make use of the STL with vector and unique_ptr (or if unnecessary shared_ptr):
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <memory> // unique_ptr
#include <vector>
int main(){
sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);
std::vector<sf::Vertex> sh(3);
sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));
std::unique_ptr<sf::RenderTexture> shipRTex(new sf::RenderTexture);
if(!shipRTex->create(64,64)){
return -1;
}
shipRTex->clear(sf::Color::Transparent);
shipRTex->draw(sh.data(), sh.size(), sf::Triangles);
shipRTex->setSmooth(false);
shipRTex->display();
sf::Texture shipTex;
if(!shipTex.create(64,64)){
return -1;
}
shipTex = shipRTex->getTexture();
sf::Sprite ship(shipTex);
ship.setColor(sf::Color(255,255,255,255));
ship.setOrigin(32, 32);
ship.setScale(1.f/4.f, 1.f/4.f);
ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);
window.setVerticalSyncEnabled(true);
window.setFramerateLimit(60);
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if(event.type == sf::Event::Closed){
window.close();
}
}
window.clear(sf::Color(127,63,31,255));
window.draw(ship);
window.display();
}
return 0;
}
Note: Since unique_ptr is an RAII object, the resources will automatically get released when the scope is left.
But I think your idea was to free the memory as soon as possible, thus when the render texture isn't needed anymore. This could also be easily done with smart pointers and some brackets:
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <memory> // unique_ptr
#include <vector>
int main(){
sf::RenderWindow window(sf::VideoMode(400,300), "Placeholder", 7);
sf::Texture shipTex;
if(!shipTex.create(64,64)){
return -1;
}
// RenderTexture scope
{
std::vector<sf::Vertex> sh(3);
sh[0] = sf::Vertex(sf::Vector2f(0,64), sf::Color(255,127,64,255));
sh[1] = sf::Vertex(sf::Vector2f(32,0), sf::Color(255,191,127,255));
sh[2] = sf::Vertex(sf::Vector2f(64,64), sf::Color(255,127,64,255));
std::unique_ptr<sf::RenderTexture> shipRTex(new sf::RenderTexture);
if(!shipRTex->create(64,64)){
return -1;
}
shipRTex->clear(sf::Color::Transparent);
shipRTex->draw(sh.data(), sh.size(), sf::Triangles);
shipRTex->setSmooth(false);
shipRTex->display();
shipTex = shipRTex->getTexture();
}
sf::Sprite ship(shipTex);
ship.setColor(sf::Color(255,255,255,255));
ship.setOrigin(32, 32);
ship.setScale(1.f/4.f, 1.f/4.f);
ship.setPosition((float)window.getSize().x/2, (float)window.getSize().y/2);
window.setVerticalSyncEnabled(true);
window.setFramerateLimit(60);
while (window.isOpen()){
sf::Event event;
while (window.pollEvent(event)){
if(event.type == sf::Event::Closed){
window.close();
}
}
window.clear(sf::Color(127,63,31,255));
window.draw(ship);
window.display();
}
return 0;
}
Would be interesting to see which versions work and which don't.