So I have A sfml program and I am trying to have multiple windows open at once. I know I had a functioning code but I couldn't have more than one main loop running at a time. I have made a vector of pointers to windows and a vector of a structure I made. Inside the function I'm trying to use to replace the while loop that would be running in each open window I have a for loop inside the function that should run through whole vector and render everything. I've narrowed down the code generating the error to either the stepWindows function or my function that adds a new window. I have no idea what I did wrong but there are no compiler errors however, the debug console is having a error:
An internal OpenGL call failed in Texture.cpp(98).
Expression:
glFlush()
Error description:
GL_INVALID_OPERATION
The specified operation is not allowed in the current state.
Here is my StepWindows Function I made it inside the class MakeKey
void MakeKey::StepWindows(vector <MakeKey::NewKey> KeyArray, vector <sf::RenderWindow*> WindowArray)
{
for (int i{ 0 }; i > KeyArray.size(); i++)
{
cout << "Inside Step Windows For Loop" << endl;
WindowArray[1]->setActive(true);
WindowArray[1]->clear(sf::Color::Transparent);
WindowArray[1]->draw(KeyArray[1].Sprite);
WindowArray[1]->display();
}
}
Here is the section that makes a new window
void MakeKey::DrawKey(string input, vector <MakeKey::NewKey>* KeyArray, vector <sf::RenderWindow*>* WindowArray)
{
MakeKey::NewKey Key;
if (input == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (input == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
//Ect
sf::RenderWindow window(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
sf::RenderWindow* windowPoint = &window;
//Make Transparent
const unsigned char opacity = 1000;
KeyArray->push_back(Key);
WindowArray->push_back(&window);
cout << "KeyArray Has " << KeyArray->size() << " Elements\n" << "WindowArray Has " << WindowArray->size() << " Elements" << endl; //for debugging
}
And of course my main
int main()
{
static vector <MakeKey::NewKey> KeyArray;
static vector <MakeKey::NewKey>* KeyArrayPointer = &KeyArray;
static vector <sf::RenderWindow*> WindowArray;
static vector <sf::RenderWindow*>* WindowArrayPointer = &WindowArray;
sf::RenderWindow window(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::Default);
MakeKey MakeKey;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
//Key Presses
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A)
MakeKey.DrawKey("A", KeyArrayPointer, WindowArrayPointer);
else if (event.key.code == sf::Keyboard::D)
MakeKey.DrawKey("D", KeyArrayPointer, WindowArrayPointer);
//Ect
}
if (event.type == sf::Event::Closed)
window.close();
}
MakeKey.StepWindows(KeyArray, WindowArray);
}
return EXIT_SUCCESS;
}
Thanks guys
In your DrawKey method, you appear to be creating a new window each time you press a key (as a temporary, which will be destroyed at the point DrawKey returns)
sf::RenderWindow window(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
You then take the address of that temporary, and store it's address.
WindowArray->push_back(&window);
which means WindowArray now holds a pointer to a dead object. Something about the whole set up looks very fishy to me.
I'm no expert on sfml, but I'd have assumed that if you needed to have multiple windows open, this would be the way to do it:
// just store the windows in a normal array
static std::vector<sf::RenderWindow> windows;
// add main window (and do this if you need to add more windows)
windows.emplace_back(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::Default);
// keep the app running while a window is open.
while(!windows.empty())
{
for(auto window = windows.begin(); window != windows.end(); ++window)
{
if(!window->isOpen())
{
// if main window closed, clear all windows (and exit main loop)
if(window == windows.begin())
{
windows.clear();
}
else
{
// erase the window that was closed
window = windows.erase(window);
}
}
else
// process all queued events for window
{
sf::Event event;
while (window->pollEvent(event))
{
//Key Presses
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A)
MakeKey.DrawKey("A", KeyArray, windows);
else if (event.key.code == sf::Keyboard::D)
MakeKey.DrawKey("D", KeyArray, windows);
//Ect
}
if (event.type == sf::Event::Closed)
{
window->close();
break;
}
}
}
MakeKey.StepWindows(KeyArray, windows);
}
}
This would imply a few changes to your drawkey function (I'm assuming the intention is to create a new window each time a key is pressed??). You would probably find it easier to pass references to the vectors, instead of pointers to the vectors.
void MakeKey::DrawKey(
std::string input,
std::vector<MakeKey::NewKey>& KeyArray, //< pass by reference
std::vector<sf::RenderWindow>& WindowArray) //< pass by reference
{
MakeKey::NewKey Key;
if (input == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (input == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
//Ect|
/// << add the window to the array >>
WindowArray.emplace_back(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
//Make Transparent
const unsigned char opacity = 1000;
KeyArray.push_back(Key);
std::cout << "KeyArray Has " << KeyArray.size() << " Elements\n" << "WindowArray Has " << WindowArray.size() << " Elements" << std::endl; //for debugging
}
Your step windows function is a little confusing, so I assume you are trying to do something like this?
void MakeKey::StepWindows(const std::vector <MakeKey::NewKey>& KeyArray, std::vector <sf::RenderWindow>& WindowArray)
{
for (int i{ 0 }; i < KeyArray.size(); i++) {
cout << "Inside Step Windows For Loop" << endl;
// are you sure you only want to do this for window 1?
// It would sort of make sense to do this for window[i + 1]??
// but you will need to ensure that when you erase a window above,
// you also erase the corresponding element from the key array???
WindowArray[1 + i]->setActive(true);
WindowArray[1 + i]->clear(sf::Color::Transparent);
WindowArray[1 + i]->draw(KeyArray[1].Sprite);
WindowArray[1 + i]->display();
}
}