Passing the framework as an keyboard parameter

The following is throwing an access violation exception:

// In main.cpp
framework.define_key("escape", "Closes the framework", Keys::KeyDown_Escape, &framework);

// In Keys.cpp
void Keys::KeyDown_Escape(const Event* senderEvent, void* data)
{
   PandaFramework framework = (PandaFramework&)data;
}

When the escpae key is pressed. Just to clear things up, I’ve pushed my key press event handlers to another file, which works just fine. I can set a breakpoint in that function, and the framework object seems fine (it has data). But as soon as I step out of the function, I get that exception.

Also, I had to type this code in manually (my wireless adapter died on the computer I’m working on). I’m pretty sure I got it right, but I wanted to point it out just in case.

So what might cause this exception?

Are you sure you didn’t mean to write:

PandaFramework &framework = (PandaFramework&)data;

The way you wrote it, it creates a new PandaFramework instance and uses the copy constructor to initialize it. I have no idea if that will work; it’s certainly not the intended way to use PandaFramework, and it doesn’t surprise me that it would crash. The way I wrote it, it creates a PandaFramework reference to the existing object, which is a completely different thing.

You sure you want to work in C++? :slight_smile:

David

Thanks, that was it.

I’m a little rusty with C++, which is the point of my excursion into Panda3D, to get re-acclimated with the language. Maybe Panda3D’s not the right platform for this? I don’t think that’s the case, as I think the above problem would have surfaced in any other environment, and I’d really like to continue with Panda (it’s been really great, so far). So, yeah, I’m sure, but I’m open to suggestions.

My app is still crashing, and I’m pretty sure it’s because I’m calling framework.close_framework() in that callback function. My main loop looks like this:

while (framework.do_frame(currentThread))
{
// stuff
}

I’m guessing there’s a better way to close the app, or at least exit out of the main loop. Some way to tell do_frame to return false? Something a bit gentler, perhaps?

The code for PandaFrame::do_frame() looks like this:

////////////////////////////////////////////////////////////////////
//     Function: PandaFramework::do_frame
//       Access: Public, Virtual
//  Description: Renders one frame and performs all associated
//               processing.  Returns true if we should continue
//               rendering, false if we should exit.  This is normally
//               called only from main_loop().
////////////////////////////////////////////////////////////////////
bool PandaFramework::
do_frame(Thread *current_thread) {
  nassertr(_is_open, false);

  _task_mgr.poll();

  return !_exit_flag;
}

Which suggests looking for a function that sets _exit_flag, and here it is:

////////////////////////////////////////////////////////////////////
//     Function: PandaFramework::set_exit_flag
//       Access: Public
//  Description: Sets the flag that indicates it is time for the
//               application to exit.  The application will actually
//               exit at the end of the current frame.
////////////////////////////////////////////////////////////////////
INLINE void PandaFramework::
set_exit_flag() {
  _exit_flag = true;
}

To learn your way around the Panda code in C++, it’s helpful to be comfortable reading the C++ code. :slight_smile:

David

Fair enough.

So let’s talk Python, then. I know the tutorials, and you yourself (though perhaps you’ve indeed written some/all of the tuotirals?), say that it’s better to do more Python, than C++. What would that look like? I see no merrit in calling simple C++ functions from Python, one might as well write the whole thing in Python, then. Maybe I’m wrong about that, though.

What all is possible with a hybrid app, such as is suggested (unless the “only use a little C++” is meant as a carrot on a stick)? What pieces would it be advised to do in C++ instead of Python, and vice versa, and why?

This is a little weird. According to my debugger, framework.set_exit_flag() doesn’t appear to modify framework._exit_flag at all. It’s true before and after I call it. However, if I call set_exit_flag within the actual main loop, the next do_frame evaluates to false (and the loop ends), but if I call it from within my Callback, do_frame marches on. Again, in both situations, framework.exit_flag is set to true both before and after the call to set_exit_flag, if my debugger is to be believed.

Any thoughts?

True enough, especially if you’re just talking about simple little C++ functions. And why not write the whole thing in Python, after all?

Let’s talk about the advantages and disadvantages of each language.

Python:

  • Very rapid development.
  • Relatively slow execution time.

C++:

  • Very rapid execution time.
  • Relatively slow development.

So, the usual development pattern is to do as much development as possible in Python, because development time is usually the most valuable investment in a project. If, in the course of development, you come across some function that is simply too slow to run in Python, then you can translate it to C++ and continue development of the rest of the project in Python.

But in practice, these functions that have to be written in C++ are very rare. Most of them have already been written for you, and they’re the core of Panda itself. Within Disney, we have written two full-featured MMO’s using almost entirely pure Python code, plus what Panda has to offer.

There are other reasons to prefer one language over another, of course; as you’ve said, you have your reasons. There’s no reason not to write a project in Panda using entirely or mostly C++. Such a project will take longer to develop than the same project developed using entirely or mostly Python, but maybe you’re willing to make that tradeoff.

I don’t have a lot of faith in the values reported by the MSVC debugger. Because Panda is compiled in Release mode, the debugger gets confused when it tries to examine the stack, and very frequently reports incorrect values. You’d be better off using cerr statements to verify the values of different variables at runtime. Or, you could recompile Panda (and Python, and all of the third-party libraries you care about) in Debug mode.

As to why it doesn’t appear to work within your Callback, that I couldn’t say. Are you sure you’ve got the right pointer to framework?

David

First of all, thank you for your advice, and all of your help with my problems.

Tonight, I’ll get a project up and running in Python, and then make my decision. My goal, as I’ve said, is to get back into C++, but maybe it’s a bit much to learn both Panda and to pick C++ back up simultaneously. I suppose I could do one project in Python, and then another in C++/Python. It would be very educational to use one platform across two different languages, especially when both situations will likely require the use of both languages. And I’m not THAT out of it, I’ve just been in C# land for a few years, so I’ve not needed to worry about implicit copy constructor calls and the like. That, and the reference to a pointer of references which refer to pointers of references, way of thinking.

Pretty sure. I’m passing a reference to the framework (&framework) to the method. Should I instead do something like *framework? To be honest, I don’t even remember if such a thing is even valid code. I’m not at home right now, or I’d try it.

Could the problem be that the framework variable is global?

I don’t know why that would cause a problem. It does point out that you don’t actually need to pass around its pointer, though–you could just access the global value within your callback.

David

They aren’t in the same file.

Well, declare it as an “extern PandaFramework framework” in your other file, then. Still, probably not the problem, since presumably you’re passing around the pointer correctly; and there’s nothing wrong with having a global, in any case.

David

What’s left, then? A problem with define_key? When I get home, I’ll try and post the exact text of my code. I’ll burn it to a CD if I have to, as my new wireless NIC still hasn’t arrived.

I don’t think the reference is getting passed in properly, though. I tried it with a boolean reference, and (again, this is relying on the debugger) it’s value was true coming and going out, whereas the variable passed in was set to false before and after the call.

Why don’t you try spawning some cerr statements to check whether the debugger is actually telling the truth?

Okay, here:

http://rafb.net/p/ZJFbZL30.html

Is my complete code. Using cerr, I was able to verify two things:

  1. The value before the assignment in the callback was 148, which for a boolean is a little strange, so I’m thinking the reference was not getting set properly.

  2. Switching to this code:

	bool* exitFlag = (bool*)data;

	*exitFlag = true;

Works correctly.

However, cerr also verified that the framework.set_exit_flag(); in the main loop is getting called:

	while (framework.do_frame(currentThread))
	{
		double ticks = clock->get_real_time();

		MainLoop(ticks);

		if (exitFlag == true)
		{
			cerr << "Exit flag is true!" << endl;

			framework.set_exit_flag();
		}
	}

	framework.close_framework();

	return 0;

But the program is not exiting. I can even do the keypress event again. Any ideas as to what’s up there?

Oops, the link is dead. Did I take too long to try to take a look at it?

David

Alright I hate to bring up an old thread… but I am running into a little problem I can’t seem to figure out.

Regarding the way pateras moved his key event handlers to another file…
I also did this in an attempt to clean up my code a little bit. However I am getting an error that I cannot quite figure out.

The error I get is:

Any idea what little thing I could possibly be messing up to cause this compiling error?

Thanks in advance.

It sure does sound like you forgot to include the () following a function name. Were you trying to call a function, or were you trying to take its address?

David

Well I am using it in the define_key call… so I am trying to take its address I suppose. Pointers in c++ are one of my weaknesses that I am working on. So any help with that would be great. Here is the line of code that I get the error on:

pFramework->define_key("escape", "Quit", KeyEvents::KeyDown_Escape, 0);

And like I said before KeyEvents is another class which I have created that has the function:

void KeyDown_Escape(const Event* theEvent, void* data)

Two things, then. First, you should prefix the function name with a “&” to clarify that you are taking its address, and not trying to call it. But second, and more important, you must declare the method “static” so you can pass its addrses as a C-style function. (If you don’t declare it static, it takes a hidden “this” pointer, which means it doesn’t match the prototype defined by EventHandler.)

Of course, a static method is inconvenient, because it doesn’t receive a “this” pointer. That’s what the extra parameter is for. If you need your event handler to do anything to your instance, pass this as the extra parameter.

David