Missing implementation: PythonThread::call_python_func()

When I try to call this function, I get a layout error.

p3imgui.obj : error LNK2019: unresolved external symbol "public: static struct _object * __cdecl PythonThread::call_python_func(struct _object *,struct _object *)" (?call_python_func@PythonThread@@SA
PEAU_object@@PEAU2@0@Z) referenced in function "public: virtual void __cdecl PImGui::do_callback(class CallbackData *)" (?do_callback@PImGui@@UEAAXPEAVCallbackData@@@Z) [D:\Code\Cpp\ImGuiIntegration\
Variant_6\temp\imgui.vcxproj]
D:\Code\Cpp\ImGuiIntegration\Variant_6\temp\Release\imgui.pyd : fatal error LNK1120: 1 unresolved externals [D:\Code\Cpp\ImGuiIntegration\Variant_6\temp\imgui.vcxproj]

At the same time, I have connected all the available libraries that were built after compiling Panda3D with the python support flag. Should I compile cpp?

target_link_libraries(imgui libp3pystub)
target_link_libraries(imgui libp3dtool)
target_link_libraries(imgui libp3interrogatedb)
target_link_libraries(imgui libp3dtoolconfig)
target_link_libraries(imgui libpanda)
target_link_libraries(imgui libpandaexpress)

It’s not a class that’s available in the public libraries. It’s part of the Python bindings in core.pyd, because the code is dependent on the specific version of Python. You would have to link against core.pyd, but I don’t recommend doing that.

Do you need this method for some specific reason?

It’s hard for me to give a reason, because I’m experimenting with running python functions on the C++ side. However, there is a minor side issue right now. Similar in this discussion, where I actually learned about this feature.

The problem is that after calls on the C++ side, the objects that the C++ thread interacted with remain blocked. The problem is that after calls on the C++ side, the objects that the C++ thread interacted with remain locked. However, partially, since nothing happens on the first access (for example, to the list), on the second attempt I can access the object on the python side guaranteed. So I thought about using this feature.

If you want interrogate to release the GIL during your call, put the BLOCKING keyword before your method signature in the header file.

It means you need to grab the GIL again when you make a call back to Python. You don’t need call_python_func, it was mostly important back when we used a different threading model. You can just use PyObject_CallMethod and friends.

I added BLOCKING before the call method, but now it causes the program to crash when trying to interact.

Maybe the problem is that I’m using the do_callback() method a little differently, since I’m not using the PythonCallbackObject passed as the call argument. At the same time, I lock the GIL myself and release it, because without it the program crashes.

If you add BLOCKING you need to grab the GIL before making any calls to Python, so you’re probably not doing that.

Maybe you can try to describe the problem a bit better, I don’t understand what you’re currently trying to solve.

I can’t give you a clear picture of what’s going on yet, because I have no experience using debuggers. I’m just experimenting now and I’m encountering strange behavior, but I’m not sure if the problem is with interrogate. I think we need a test binary build where the problem will be obvious in order to continue the discussion, I’m working on it now.

@rdb I think I’ve found a clue, I guess the problem isn’t with threads or the GIL. Accordingly, this is not an interrogate problem, but I am not completely sure.

I made a video that shows that the sequence of button processing events is being disrupted.

Each button press generates a type event - pressing 0 and releasing 8. However, this order is being disrupted, as it seems to me, due to the incorrect logic of this patch to disable input. I think the work of this patch should be somehow synchronized with the frames, but I have no idea if I understand this problem correctly.

Just in case, I created a runnable build with the source code.

I don’t think it’s related to that patch, but I don’t know what it is related to.

Please note that if you do this:

win.get_input_device(0).get_button_events()

you “steal” the events from the input device. Panda’s own data loop as well as your p3imgui system will no longer see those events. Could that be the problem? The system is designed so that you create a DataNode and insert into the data graph if you want to listen for events. Or you should use MouseWatcherRegion to hook into the MouseWatcher system, just like PGui, which makes it play nice with other GUI systems. You can override press(), release() etc virtual methods then.

Also, I don’t know if it is the problem, but I would always do this in two lines, to make sure a reference count to the ButtonEventList remains:

        event_list = win.get_input_device(0).get_button_events()
        for event in event_list.events:

There is also something weird in your C++ code, although it does not work out to be a problem in this case:

        if (button_event_list->get_num_events() >> 0){

This should probably be > 0, because >> is the right-shift operator.

This also has a memory leak:

PyObject_CallObject(instrution, Py_BuildValue("(i)", input_control));

Should be:

PyObject *args = Py_BuildValue("(i)", input_control);
PyObject *result = PyObject_CallObject(instrution, args);
Py_DECREF(args);
Py_XDECREF(result);

Thanks for analyzing the code. But just in case, I’ve checked all your findings and it doesn’t change anything.

I know about the special feature of the get_button_events() method, it is specified in the API.

In fact, this feature prompted me to create this patch to create a priority for accessing the list. In fact, this patch is not used in this test build, as it is relevant for ShowBase. Therefore, it does not matter in the problem that is reflected in the video, I even removed the change_control method from the code to be sure.

Potentially, however, the problem may be in the current way of handling keyboard events. I believe that interested listeners should be registered in the Window class, to which Windows should pass input events (GUI and Game logic). Or way, as an option, not to clear the list of key events when it is requested, but to clear it at the end of the frame.

For example, what can be implemented using the additional flag get_button_events(true)

The design of Panda3D is that interested systems should register their listeners with the data graph or with the MouseWatcher, these are more powerful systems. However, I can understand the appeal of a simpler system.

I notice you handle events in the draw callback. You are not using the multi-threaded rendering pipeline (threading-model), right? That would make the timing undeterministic.

In my opinion, it is better to use the system the way it was designed, but I don’t know if that will solve your problem in this case.

I planned that Dear ImGui integration would not depend on the availability of ShowBase.

I’m not sure if multithreaded rendering mode will lead to unpredictable behavior. Because by itself, it does not involve multiple rendering of the contents of the display area in each pass. If this is not the case, then yes, there will be problems.

However, I believe that the current implementation of the input is clumsy because it depends on dynamic circumstances. Since the node data system can be changed arbitrarily by the user, it is not very reliable and can break at any time.