Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: How to recreate the window when using SFML ImGui?  (Read 4054 times)

0 Members and 1 Guest are viewing this topic.

Fx8qkaoy

  • Newbie
  • *
  • Posts: 42
    • View Profile
How to recreate the window when using SFML ImGui?
« on: February 11, 2020, 07:46:40 pm »
I want to add to my game the functionality to change window stuff, and in this example I will refer to resolution. I did it some months / years ago, but now I'm failing. Below is some code to understand what I'm doing. Comments before each block exaplains where the calls happen

Code: [Select]
// Beginning of main()
scene::window = new sf::RenderWindow(sf::VideoMode(1600, 900), "Test");
scene::view = new sf::View(scene::window->getView());
scene::view->setSize(sf::Vector2f(scene::size.x, scene::size.y)); // Pixel-art game, so I want bigger units (size.x < 1600)

// In a network thread
void setPos(float x) {
player->sprite->setPosition(x, scene::band * 1.5f);
scene::view->setCenter(x, 0);
scene::window->setView(*scene::view); // All of these makes the camera follow the local player; also is the first one who sets a custom sf::View on the window
}

// After handling window events, clearing the screen, drawing SFML related stuff, but before drawing (ImGUI is a lib that handles button clicks at the same time with drawing, and I draw ImGui stuff after all my sprites); happens on a click
scene::window->create(sf::VideoMode(900, 900), "Test");

The usage of network *thread* doesn't seem to have negative impact, since before pressing everything works right. What happens: after the last block is ran, the window is recreated with the right resolution, but everything is black. I tried resetting the view:

Code: [Select]
scene::window->create(sf::VideoMode(900, 900), "Test");
scene::view = new sf::View(scene::window->getView());
scene::view->setSize(sf::Vector2f(scene::size.x, scene::size.y));
scene::window->setView(*scene::view); // I assure that at (0, 0) is stuff drawn

I tried recreatting a sprite with its texture:

Code: [Select]
scene::window->create(sf::VideoMode(900, 900), "Test");
scene::view = new sf::View(scene::window->getView());
scene::view->setSize(sf::Vector2f(scene::size.x, scene::size.y));
scene::window->setView(*scene::view);

// The block is copied from the initial generation, only the final instruction is changed from push_back() to modifying the original one, so I can assure there's no problems with loading it
auto bgTex = new sf::Texture;
bgTex->loadFromFile("texs/bg.png");
auto bg = new sf::Sprite(*bgTex);
bg->setPosition(sf::Vector2f(-scene::size.x / 2.f, -scene::size.y / 2.f));
scene::metal[0] = bg; // The background is supposed to take the whole screen on (1600, 900)

The same result. If it helps, ImGui actually still works like nothing happened, it's just on top of a black screen. Everything is up to date, running on VS2019, SFML_STATIC. I have another SFML instance in the system background since the server uses its network capabilities (no window)
« Last Edit: February 15, 2020, 09:40:30 am by Fx8qkaoy »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: How to change window attributes (such as res and style) safely?
« Reply #1 on: February 14, 2020, 03:22:27 pm »
If you use threads, it's your responsibility to properly protect shared objects. SFML doesn't provide any guarantees on multi-threading.
Most of the time the best advice is to not use multiple threads, but if that's not possible, you'll have to learn about locks/mutex and general parallel programming patterns.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: How to change window attributes (such as res and style) safely?
« Reply #2 on: February 14, 2020, 03:53:48 pm »
You should experiment with simpler code, to easily spot what you're doing wrong. And eventually, you'll have a complete and minimal code reproducing the problem, that you can post here.

And you should really avoid all these dynamic allocations (new sf::Sprite, new sf::View, ... it hurts ;D); that will also avoid all these memory leaks (unless your actual code has proper "delete" everywhere).
Laurent Gomila - SFML developer

Fx8qkaoy

  • Newbie
  • *
  • Posts: 42
    • View Profile
Re: How to change window attributes (such as res and style) safely?
« Reply #3 on: February 15, 2020, 09:39:45 am »
Thx for helping! I forgot to check my code with a minimal example. Seems like the problem was since I was doing my window recreation after stuff was already drawn on it:

Code: [Select]
#include <SFML/Graphics.hpp>
#include <imgui/imgui.h>
#include <imguiSFML/imgui-SFML.h>
int main() {
sf::RenderWindow window(sf::VideoMode(1600, 900), "Window");
ImGui::SFML::Init(window);
auto bg = new sf::Sprite;
{
auto tex = new sf::Texture;
tex->loadFromFile("resources/bg.png");
bg->setTexture(*tex);
}
sf::Event event;
sf::Clock clock;
while (window.isOpen()) {
while (window.pollEvent(event))
ImGui::SFML::ProcessEvent(event);
ImGui::SFML::Update(window, clock.restart());
window.clear();
window.draw(*bg);
ImGui::Begin("Inside window");
if (ImGui::Button("Test"))
window.create(sf::VideoMode(800, 450), "Window");
ImGui::End();
window.pushGLStates();
ImGui::SFML::Render();
window.popGLStates();
window.display();
}
}

Changing it to this solved the problem:

Code: [Select]
#include <SFML/Graphics.hpp>
#include <imgui/imgui.h>
#include <imguiSFML/imgui-SFML.h>
int main() {
sf::RenderWindow window(sf::VideoMode(1600, 900), "Window");
ImGui::SFML::Init(window);
auto bg = new sf::Sprite;
{
auto tex = new sf::Texture;
tex->loadFromFile("resources/bg.png");
bg->setTexture(*tex);
}
sf::Event event;
sf::Clock clock;
while (window.isOpen()) {
while (window.pollEvent(event))
ImGui::SFML::ProcessEvent(event);
ImGui::SFML::Update(window, clock.restart());
window.clear();
ImGui::Begin("Inside window");
if (ImGui::Button("Test"))
window.create(sf::VideoMode(800, 450), "Window");
ImGui::End();
window.draw(*bg);
window.pushGLStates();
ImGui::SFML::Render();
window.popGLStates();
window.display();
}
}

I also forgot to mention that on my original code the window was recreated in the main thread, not the network one. I will update the title for this post to be more suggestive about the problem so other people can find it easier