sf::RenderTexture displays upside down
kevvo1288 opened this issue ยท 15 comments
I'm not sure if this is the same issue as #11 but RenderTextures seem to be flipped upside down. I've attached a minimal program to produce the issue. The sprite shows right-side up if I render it using RenderWindow::draw() but if I use ImGui::Image() it is upside down. Rendering the raw sf::RenderTexture using ImGui::Image() also results in an upside down image.
If I do the same test using an image loaded from a file into a sf::Texture instead of the sf::RenderTexture, everything renders just fine.
#include "imgui.h"
#include "imgui-SFML.h"
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(640, 480), "");
window.setFramerateLimit(60);
ImGui::SFML::Init(window);
bool show = true;
sf::RenderTexture renderTexture;
if (!renderTexture.create(32, 32))
{
std::cout << "error renderTexture\n";
return 1;
}
sf::Sprite sprite(renderTexture.getTexture());
sf::RectangleShape rect(sf::Vector2f(16, 16));
rect.setFillColor(sf::Color::White);
rect.setPosition(0, 0);
renderTexture.clear(sf::Color::Green);
renderTexture.draw(rect);
renderTexture.display();
sf::Clock deltaClock;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
ImGui::SFML::ProcessEvent(event);
if (event.type == sf::Event::Closed) {
window.close();
}
}
ImGui::SFML::Update(window, deltaClock.restart());
ImGui::Begin("Sprite Test");
//ImGui will render this upside down
ImGui::Image(sprite);
ImGui::End();
ImGui::Begin("RenderTexture Test");
//ImGui will render this upside down
ImGui::Image(renderTexture.getTexture());
ImGui::End();
window.clear(sf::Color::Black);
//SFML renders ok
window.draw(sprite);
//But IMGUI seems to render these upside down
ImGui::SFML::Render(window);
window.display();
}
ImGui::SFML::Shutdown();
}
Okay, I'll see what I can do soon. Are you using the latest version of SFML, btw?
Yes, sorry I should have said:
SFML 2.4.2 VC++ 14 (VS 2015) 32 bit
Windows 7
Sorry, I forgot about the issue. So, the problem is really here and it exists because RenderTexture stores the texture upside down. The sprite renders correctly, because textures store flag about whether it has pixels flipped or not.
sf::Texture::Bind handles this case, but for some reason if I use texture pointers instead of native handles in imgui-SFML code, things get really glitched. I'll take a closer look at the issue in a few days and report what I will found.
UPD: No fix found :(
For what it's worth, I've worked around this temporarily by just copying all the Image(sf::Texture...)
overloads, replacing with Image(sf::RenderTexture...)
and flipping the UV's. Seems to give the expected result although I'm sure there are smarter ways to work around this....
Yes, I think that's the right way to do it for now. The problem is that if the user passes renderTexture.getTexture()
instead of renderTexture
, it'll just be sf::Texture
and we'll have no way to say if it came from sf::RenderTexture or not (inside ImGui::SFML::Render
).
I think I'll overload Image
with sf::RenderTexture
for now. That's the best I can do about it, I think. Will investigate further later.
Didn't see the code, but usually a flipped texture is 90% of the time due to a forgotten ".display()" call...
No, here the problem is that RenderTexture stores flipped texture. I think I need to add overload for it which will flip it, just like JohnyPtn said. :)
Uh huh, this is part of the 10% :P
example solution:
void Image(const sf::RenderTexture& texture, const sf::Vector2f& size, const sf::FloatRect& textureRect,
const sf::Color& tintColor, const sf::Color& borderColor)
{
sf::Vector2f textureSize = static_cast<sf::Vector2f>(texture.getSize());
ImVec2 uv0(textureRect.left / textureSize.x, (textureRect.top + textureRect.height) / textureSize.y);
ImVec2 uv1((textureRect.left + textureRect.width) / textureSize.x, textureRect.top / textureSize.y);
ImGui::Image((void*)texture.getTexture().getNativeHandle(), size, uv0, uv1, tintColor, borderColor);
}
Also found this flipping issue already reported in 2010 and no solution yet for me or any other designer. I really need to render the menu-card to renderTextures, then add them to the sf::View to create a swipe experience... else sfml is really too slow, especially in Chinese. My menu card is suddenly upside down :-( Because of lower performance compare to SDL, this verticle shit and not able to update parts of the screen I have to stick with SDL, although SFML seems to have a very clear interface for C++... too bad. :-( I hope they will improve in the future and also change to utf-8 because utf-32 becomes a nightmarre.
@barthoukes does the solution from @JonnyPtn work for you for ImGui-SFML?
I'm not really sure where to start with that comment... but here goes:
- This is just an SFML binding for imgui
- You can pretty much copy and paste the code in my previous comment to get your problem solved
And regards to your SFML comments:
- I don't see how being in Chinese affects the speed of SFML
- Do you have any tests to back up your "SDL is faster" claim? It's hard to compare, but common knowledge is that SFML is slightly faster. I'd love to see some benchmarks
- What's "this verticle shit" and which parts of the screen can't you update?
- sf::String can convert to utf8 for you, that's exactly what it's designed for.
Most of your comment Is SFML related, so best not to discuss it here anyway, join us in the SFML Discord (or IRC) channel if you want to discuss them
Hi @eliasdaler ,
I bumped into the same flipped texture problem...
I could not figure out where to insert @JonnyPtn solution, because his ImGui::Image call did not worked for me... but I added this to imgui-SFML.cpp :
void Image(const sf::RenderTexture& texture,
const sf::Color& tintColor, const sf::Color& borderColor) {
ImTextureID textureID =
convertGLTextureHandleToImTextureID(texture.getTexture().getNativeHandle());
ImGui::Image(textureID, static_cast<sf::Vector2f>(texture.getSize()),
ImVec2(0, 1), ImVec2(1, 0), tintColor, borderColor);
}
and this in imgui-SFML.h
IMGUI_SFML_API void Image(const sf::RenderTexture& texture, const sf::Color& tintColor = sf::Color::White, const sf::Color& borderColor = sf::Color::Transparent);
and it worked. So if it can help someone... or if you want to update your code...
Anyway, thx for your code @eliasdaler , it's great !
thanks @JonnyPtn, your solution solved the problem, now everything works correctly.
Please check out this branch:
https://github.com/eliasdaler/imgui-sfml/tree/render-texture-fixes
UPD: branch deleted, fix is here: ee41e16
So, here's the thing. I can add sf::RenderTexture
overload which works properly, however it won't work for sf::Sprite
which has a texture from sf::RenderTexture
assigned, so if I take the code from @kevvo1288 and add these lines:
ImGui::TextUnformatted("RenderTexture");
ImGui::Image(renderTexture);
ImGui::SameLine();
ImGui::ImageButton(renderTexture);
ImGui::TextUnformatted("Texture");
ImGui::Image(*sprite.getTexture());
ImGui::SameLine();
ImGui::ImageButton(*sprite.getTexture());
ImGui::TextUnformatted("Sprite");
ImGui::Image(sprite);
ImGui::SameLine();
ImGui::ImageButton(sprite);
This is the best I can do, because to know if the texture comes from sf::RenderTexture
or not, we need access to sf::Texture::m_pixelsFlipped
which is private.
Merged the fix into the master: ee41e16
I've also added a workaround if you really need to use sf::RenderTexture
with sf::Sprite
(you basically have to copy it to a new sf::Texture
... not perfect, but it works. See README for details)
The oldest bug is now closed. Sorry for the huge procrastination on my part.