unhandled exception on framework.do_frame()

Here is a simplified version of my code.
This code is written to show a splash screen (press escape to leave splash), then jump to login screen (pass “admin” and “pass” as login information)

The problem is; program throws an unhandled exception when it comes to framework.do_frame() of the second screen.
The order changes nothing, it happens on 2nd screen.( splash > login or login > splash)

But if you alter code to show only one screen (i.e. splash > splash or login > login) no exception happens.

Any suggestions?

Here is the code…

#include "pandaFramework.h" 
#include "pandaSystem.h" 
#include "PGButton.h" 
#include "MouseButton.h" 
#include "PGEntry.h"

int _fLoginMain(int argc, char** argv);
int _fSplashMain(int argc, char** argv);

void main (int argc, char** argv)
{
	while (1)
	{
		_fLoginMain(argc, argv);
		_fSplashMain(argc, argv);
	}
}

int _iReturnVal;
PT(PGEntry) entry1;
PT(PGEntry) entry2;
PT(TextNode) textnode;

static void _fLoginCallback(const Event *ev, void *data) 
{     
	if ( *((char*)data) == 'l')
	{
		if (entry1->get_plain_text().length() < 4) 
		{
			textnode->set_text("ERROR: \"Account Name\" must be at least 4 character");
			textnode->set_text_color(1,0,0,1);
			entry1->set_focus(1);
			entry2->set_focus(0);
		}        
        else if (entry2->get_plain_text().length() < 4)
		{
			textnode->set_text("ERROR: \"Password\" must be at least 4 character");
			textnode->set_text_color(1,0,0,1);
			entry1->set_focus(0);
			entry2->set_focus(1);
		}   
        else
		{
			textnode->set_text("Trying to login...");
			textnode->set_text_color(0,1,0,1);
			nout << "Attempting to connect to Server with credentials: (" << entry1->get_plain_text() << " , " << entry2->get_plain_text() << ")";
            // this is where the networking code will get put in 
			if ((entry1->get_plain_text() == "admin") && (entry2->get_plain_text() == "pass"))
			{
				nout << "login screen pass LOGIN";
				_iReturnVal = -2;    
			}
			else
			{
				//self.updateStatus("Invalid login name or password...")
				textnode->set_text("ERROR: Invalid account name or password...");
				textnode->set_text_color(1,0,0,1);
				entry1->set_focus(0);
				entry2->set_text("");
				entry2->set_focus(1);
			}
		}    
		return;
	}
	else	// tab
	{
		if (entry1->get_focus() == 1)
		{
			entry1->set_focus(0);
			entry2->set_focus(1);
		}
		else
		{
			entry1->set_focus(1);
			entry2->set_focus(0);
		}
	}
} 

//
// login screen...
// wait username and password match...
//
int _fLoginMain(int argc, char** argv) 
{    
	_iReturnVal = 0;
	PandaFramework framework; 

	framework.open_framework(argc, argv);    
	framework.set_window_title("Login");   
	WindowProperties props;
	props.set_size(800,400);
	props.set_fixed_size(1);
	props.set_undecorated(1);

	int flags = 0;
	WindowFramework *window = framework.open_window(props, 0);    
	// Check whether the window is loaded correctly  
	if (NULL == window) 
	{ 
	  framework.close_framework(); 
	  return _iReturnVal; 
	} 

	entry1 = new PGEntry("login name");
	entry1->setup(23,1);
	entry1->set_blink_rate(2);
	entry1->set_focus(1);
	NodePath entry1NP = window->get_aspect_2d().attach_new_node(entry1);
	entry1NP.set_scale(0.041,1,0.05);
	entry1NP.set_pos(-1.18,0,0.19); 

	entry2 = new PGEntry("password");
	entry2->setup(23,1);
	entry2->set_blink_rate(2);
	entry2->set_focus(0);
	NodePath entry2NP = window->get_aspect_2d().attach_new_node(entry2);
	entry2NP.set_scale(0.041,1,0.05);
	entry2NP.set_pos(-1.18,0,-0.09); 

	window->enable_keyboard(); // Enable keyboard detection
	framework.define_key("tab","tab",&_fLoginCallback,"t"); 
	framework.define_key("enter","login",&_fLoginCallback,"l"); 

	textnode = new TextNode("instructions");
	textnode->set_text("Login screen dummy text");
	NodePath statustext(window->get_aspect_2d().attach_new_node(textnode));
	statustext.set_pos(-1.4,0,-0.8);
	statustext.set_scale(0.05);

    Thread *current_thread = Thread::get_current_thread();
    while(framework.do_frame(current_thread)) 
	{
      if ( _iReturnVal < 0)
		  break;
    }

	// Close the framework 
	framework.close_framework();       
	return _iReturnVal; 
}


static void _fEscapeCallback(const Event *ev, void *data) 
{     
   nout << "splash screen pass QUIT "; 
    _iReturnVal = -1;    
} 

//
// splash screen...
//
int _fSplashMain(int argc, char** argv)
{    
	_iReturnVal = 0;
	PandaFramework framework; 

	framework.open_framework(argc, argv);    
	framework.set_window_title("Splash");   
	WindowProperties props;
	props.set_size(800,400);
	props.set_fixed_size(1);
	props.set_undecorated(1);

	int flags = 0;
	WindowFramework *window = framework.open_window(props, 0);    
	// Check whether the window is loaded correctly  
	if (NULL == window) 
	{ 
	  framework.close_framework(); 
	  return _iReturnVal; 
	} 

	window->enable_keyboard(); // Enable keyboard detection
	   
	framework.define_key("escape","QuitTheProgram",_fEscapeCallback,NULL); 

	textnode = new TextNode("instructions");
	textnode->set_text("Splash screen dummy text");
	NodePath statustext(window->get_aspect_2d().attach_new_node(textnode));
	statustext.set_pos(-1.4,0,-0.8);
	statustext.set_scale(0.05);
	   
    Thread *current_thread = Thread::get_current_thread();
    while(framework.do_frame(current_thread)) 
	{
      if ( _iReturnVal < 0)
		  break;
    }
/*
	//Run it 
	framework.main_loop(); 
*/
	// Close the framework 
	framework.close_framework();       
	return _iReturnVal; 
} 

I don’t think the PandaFramework class is designed to be repeatedly closed and reopened within the same application. Even if you create different PandaFramework instances. There are global systems that get cleaned up at framework.close_framework(), which might not be prepared to be created again within the same application.

Arguably, this is a poor design of the system. Why shouldn’t you be able to create a new PandaFramework if you want to? But the bigger question is, is that really what you want to do? The intention is that one PandaFramework object should exist during the lifetime of your application.

Most applications are designed to create one window during their lifetime, and to render different things to that window, when switching between different parts of the application. (The splash window is often a special case, but applications that create a splash window typically do this with low-level Window calls when they are launching, to entertain the user during the time it takes to load the rest of the application; it doesn’t make a lot of sense to use the full application toolkit to create a full-featured window for the splash window, since by that time the application has already loaded.)

So, short answer: don’t create multiple PandaFramework objects. Don’t even create multiple windows, unless there’s a good reason to do this. Just re-render different things to the same window.

David

It seems right, for PandaFramework::open_framework(…) c++ reference says:
Should be called ONCE at the beginning of the application to initialize Panda (and the framework) for use.

I think it is easier if you create one framework for char creation, one for char selection and one for the game itself. By that way all parts will be isolated and consistent in itself.
It seems it can be done by opening and closing windows. At least c++ reference does not say “create once”. :slight_smile:
The only question is key and mouse event hooks. They are binded to framework. But all the windows have their own set of keys events.
Although there is define_key(…) method there is no evidence for delete_key(…).

Anyway, if you ignore that define_key and delete_key chitchat, It seems the answer is:

Thanks…