Hi everyone,
I'm writing a code that should show more than a window at a time and, since each update of the windows is inside a while(window.isOpen()) loop, the only way I know to do it is with threads (I never used threads before and I'm using std::thread as suggested in tutorials).
The program run as it should and everything works fine, but I noticed that I need to close the opened windows in reverse order (from the last opened to the first) otherwise this message appears twice in the cmd:
Failed to activate OpenGL context: Handle non valido.
(I'm on italian windows 11)
The creation and update of each window is made in a single thread.
I think the problem could be on the variable bool _interact or std::vector sciame (which are the only shared resources between the two windows) or in the way I draw cicles in function plot (a single object moved and drawn rather than one object for each circle), but I don't know how to fix it.
Thanks a lot in advance.
Here is a minimal version of my code (The full version of the code can be found in
https://github.com/sistemicomplessi/Kuramoto):
main.cpp
int main() {
Firefly::setWindowDim(1000,700);
Firefly::setK(10);
std::vector<Firefly> sciame;
for (int i = 0; i < 1000; i++) {
sciame.push_back(Firefly(Distribution::Lorentz,1,0.5));
}
//Draw window, plot window and evolve done in separeted threads, passing sciame as reference
std::thread dThread(&Firefly::draw, std::ref(sciame));
std::thread pThread(&Firefly::plot, std::ref(sciame));
std::thread eThread(&Firefly::evolve, std::ref(sciame), true);
//wait for threads to terminate before proceding
dThread.join();
pThread.join();
Firefly::stopEvolve();
eThread.join();
return 0;
}
firefly.h (public inheritance from class oscillator, but I don't think it's important here)
#ifndef FIREFLY_H
#define FIREFLY_H
#include "oscillator.h"
#include <SFML/Graphics.hpp>
class Firefly : public Oscillator {
static double _K; //coupling strength between firefly
static sf::Vector2f _windowDim; //dimension (pixels, (x,y)) of the grid where fireflies will be placed
static bool _interaction; //toggle interaction between fireflies
static bool _evolve; //to decide when to stop evolving
sf::Vector2f _position; //position of firefly on the window
//makes the firefly (its oscillator) interact with the others
void interact(std::vector<Firefly>& system, double dt);
public:
Firefly(Distribution dist = Distribution::Lorentz, double mean = 1, double param = 998, sf::Vector2f position = sf::Vector2f(-1,-1));
//get and set functions:
static void setK(double K) { _K = K; }
static void setWindowDim(int x, int y) { _windowDim = sf::Vector2f(x,y)); }
sf::Vector2f position() { return _position; }
//calls update and interact for each element of the vector
static void evolve(std::vector<Firefly>& syst, bool saveData = true);
//break out from evolve loop
static void stopEvolve() { _evolve = false; }
//draw the system
static void draw(std::vector<Firefly>& syst);
//plot the oscillators in a complex plane
static void plot(std::vector<Firefly>& syst);
};
#endif //FIREFLY_H
firefly.cpp
#include "firefly.h"
#include <iostream>
#include <random>
#include <algorithm>
#include <fstream>
sf::Vector2f Firefly::_windowDim = sf::Vector2f(1000, 700);
double Firefly::_K = 1;
bool Firefly::_interaction = false;
bool Firefly::_evolve = true;
void Firefly::interact(std::vector<Firefly>& system, double dt) {
// do something (i think it's not important here)
}
Firefly::Firefly(Distribution dist, double mean, double param, sf::Vector2f position) : Oscillator(dist, mean, param), _position{position} {
if (position >= _windowDim) {
std::cerr << "WARN (13): position value is too high for the set window dimensions: using a random position instead.\n";
std::cerr << "Use Firefly::setWindowDim static function if you want to change the window dimensions\n";
position = sf::Vector2f(-1,-1);
}
if (position == sf::Vector2f(-1,-1)) { //default value -> random setting
std::random_device seed;
std::uniform_int_distribution<int> distX(0, _windowDim.x);
std::uniform_int_distribution<int> distY(0, _windowDim.y);
_position.x = distX(seed);
_position.y = distY(seed);
}
}
void Firefly::evolve(std::vector<Firefly>& syst, bool saveData) {
int size = syst.size();
sf::Clock clock;
double time = 0;
std::fstream fout("r-t data.txt", std::ios::out);
double dt = 0;
while(_evolve) {
dt = clock.restart().asSeconds();
for (int i = 0; i < size; i++) {
//update
syst[i].Oscillator::update(dt);
}
if (_interaction) {
for (int i = 0; i < size; i++) {
syst[i].interact(syst, dt);
}
if (saveData) {
std::cout << "Saving data\n";
fout << time << '\t' << moduleOrderParameter(syst) << '\n';
time += dt;
}
}
} //end while
fout.close();
}
void Firefly::draw(std::vector<Firefly>& syst) {
int drawSize = 5;
//load font
sf::Font arial;
if (!arial.loadFromFile("arial.ttf"))
std::cerr << "ERR(21): Couldn't load font. Check if font is present in working folder.\n";
//variables for events managing
bool showOff = false; //show/hide not-flashing (off) fireflies
double addFrequency = 1; //frequency of the new added firefly
sf::RenderWindow window(sf::VideoMode(_windowDim.x, _windowDim.y), "Fireflies");
window.setFramerateLimit(30); //less lag
//main loop (or game loop)
while (window.isOpen())
{
//reacts to Events
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::Resized) {
//view changes with window. Doing so, instead of squeezing/stretchin things, more things will be shown when resizing.
sf::FloatRect visibleArea(0, 0, event.size.width, event.size.height);
window.setView(sf::View(visibleArea));
//Let the place where fireflies spawn be the same of the window
Firefly::setWindowDim(event.size.width, event.size.height);
}
if (event.type == sf::Event::KeyPressed) {
//S : show/hide not-flashing fireflies
if (event.key.code == sf::Keyboard::S)
showOff = !showOff;
//I : toggle interraction
if (event.key.code == sf::Keyboard::I)
{
_interaction = !_interaction;
}
}
} //end react to events
window.clear(); //clear with default color (black)
//draw fireflies
int N = syst.size();
for (int i = 0; i < N; i++) {
sf::CircleShape circle(drawSize);
circle.setPosition(syst[i].position());
if (std::cos(syst[i].phase()) > 0.9) {
circle.setFillColor(sf::Color::Yellow);
window.draw(circle);
}
else if (showOff) {
circle.setFillColor(sf::Color(120,120,120)); //gray
window.draw(circle);
}
}
//draw dinamic (changing) text
sf::String dString = "\n\n\n\nPress 'I' to toggle interaction between fireflies (" + std::to_string(_interaction) + ')';
sf::Text dText(dString, arial,12);
window.draw(dText);
//refresh display
window.display();
}
}
void Firefly::plot(std::vector<Firefly>& syst) {
int windowSize = 500;
int radius = 1;
int dim = windowSize + radius*2;
//create window
sf::RenderWindow window(sf::VideoMode(dim, dim), "Plot");
window.setFramerateLimit(30); //less lag
//load font
sf::Font arial;
if (!arial.loadFromFile("arial.ttf"))
std::cerr << "ERR(32): Couldn't load font. Check if font is present in working folder.\n";
//setting background
sf::RectangleShape xAxis(sf::Vector2f(dim,1));
xAxis.setPosition(0, dim/2);
xAxis.setFillColor(sf::Color(130,130,130));
sf::RectangleShape yAxis(sf::Vector2f(1,dim));
yAxis.setPosition(dim/2, 0);
yAxis.setFillColor(sf::Color(130,130,130));
sf::Text xText("cos θ", arial, 12);
xText.setPosition(sf::Vector2f(dim-30, dim/2 + 10));
xText.setFillColor(sf::Color::Black);
sf::Text yText("sin θ", arial, 12);
yText.setPosition(sf::Vector2f(dim/2 -10, 30));
yText.setFillColor(sf::Color::Black);
yText.rotate(270);
//circle for fireflies
sf::CircleShape circle(radius);
circle.setFillColor(sf::Color::Black);
//main loop (or game loop)
while (window.isOpen())
{
//reacts to Events
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::I)
{
_interaction = !_interaction;
}
}
}
window.clear(sf::Color::White);
window.draw(xAxis);
window.draw(yAxis);
window.draw(xText);
window.draw(yText);
//draw oscillators
int size = syst.size();
for (int i = 0; i < size; i++) {
double phase = syst[i].phase();
circle.setPosition( (std::cos(phase)+1)*windowSize/2 , (std::sin(phase)+1)*windowSize/2 );
window.draw(circle);
}
//draw text
sf::Text text("Order parameter: |r| = " + std::to_string(Firefly::moduleOrderParameter(syst)),arial,12);
text.setFillColor(sf::Color::Black);
window.draw(text);
//draw arrow (r)
sf::RectangleShape line(sf::Vector2f(moduleOrderParameter(syst)*dim/2, 2));
line.setPosition(dim/2, dim/2 +1);
line.setFillColor(sf::Color::Black);
line.rotate(angleOrderParameter(syst));
window.draw(line);
//refresh display
window.display();
}
}