[SOLVED] Extending PandaNode C++ issues.

Hello! this is my first post and have multiple questions about extending PandaNode class on C++, here’s my code:

class EXPCL_PANDA_PGRAPH Scenario : public PandaNode {
    
PUBLISHED:
    Scenario(std::string name);
    Scenario(
            std::string name,
            std::string map_file_name,
            //CameraHandler::RTSCameraHandler *camera_handler,
            WindowFramework *window
            );
    
public:

    static TypeHandle get_class_type() {  
        return _type_handle;
    }

    static void init_type() {
        PandaNode::init_type();
        register_type(_type_handle, "ScenarioNode",
                PandaNode::get_class_type());
    }

    virtual TypeHandle get_type() const;
    virtual TypeHandle force_init_type();

private:
    static TypeHandle _type_handle;
};

:question: First, What does EXPCL_PANDA_PGRAPH Macro do?
:question: Second, declaring private static members results confusing to me, specially when are divided between header-source files, I solve this problem declaring again, into source file, the variable TypeHandle _type_handle and didn’t show me any errors, but, at runtime, the node type is ‘none’ (Memory allocation mistake?), the other way is creating whole function on .h file, unfortunately this didn’t work: Linker show me unsatisfied reference to that member (_type_handle) which is in the same file (:?). About that:
:question: How does Panda3D compile using private static variable members?

I would hate using Tags instead using my own node types :stuck_out_tongue:.

Thanks for reading :smiley:, any spec, please let me know.

Ups, forgot .cpp code, here’s it:

#include "panda3d/pandaFramework.h"
#include "panda3d/windowFramework.h"
#include "panda3d/nodePathCollection.h"
#include "panda3d/pandaNode.h"
#include "panda3d/pointLight.h"

#include "scenarioLoader.h"

TypeHandle Scenario::_type_handle;

Scenario::Scenario(std::string name) : PandaNode(name) {
}

Scenario::Scenario(
        std::string name,
        std::string map_file_name,
        //CameraHandler::RTSCameraHandler *camera_handler,
        WindowFramework *window
        ) : PandaNode(name) {

    NodePath np_map = window->load_model(window->get_panda_framework()->get_models(), map_file_name);
    this->add_child(np_map.node());
    np_map.set_scale(2);

    // Setup lights.
    NodePathCollection npc_map_lights = np_map.find_all_matches("**/=objectType=pointLight");

    for (int i = 0; i < npc_map_lights.size(); i++) {
        LVecBase3f empty_pos = npc_map_lights[i].get_pos();

        PointLight *pl_replacement = new PointLight("MapLight");
        NodePath np_plight = window->get_render().attach_new_node(pl_replacement);
        window->get_render().set_light(np_plight);

        np_plight.set_pos(empty_pos);
    }
}

TypeHandle Scenario::get_type() const {
    return Scenario::get_class_type();
}

TypeHandle Scenario::force_init_type() {
    Scenario::init_type();
    return Scenario::get_class_type();
}

:stuck_out_tongue: Sorry for my bad english.

Find the solution:

Need to call init_type(); to rename class-type, so, in constructor:

    // FIXME: Investigate why other Panda classes _
    // doesn't need to init_type _
    // themselves and apply to this class.
    
    if (_type_handle.get_name(this).compare ("none") == 0){
        init_type();
    }

It’s just a patch, another day I’ll correct that FIXME. Sorry for SPAM :unamused:

Panda does call init_type for every class, in an init_module function in the config_module.cxx files. But you don’t have to worry about that because they are automatically called at static init time.

You should probably do something similar, create a method that calls init_type() on all your classes and call that at static init time, using the ConfigureFn macro.
Check out the config_x.cxx files in the Panda source.

To answer your other question, EXPCL_PANDA_PGRAPH is used to control the __declspec(dllexport) or __declspec(dllimport) syntax that Windows obnoxiously requires in order to write code for DLL’s.

Since Windows requires the code to be compiled with __declspec(dllexport) while it is compiling for the DLL itself, and then __declspec(dllimport) while any code is referencing the DLL code with #include, we define this macro to change its meaning according to whether we are actually compiling libpanda.dll or some other code. You can see this happen in pandasymbols.h.

If you are adding your code directly to libpanda.dll, you should use EXPCL_PANDA_PGRAPH and ensure BUILDING_PANDA is defined when you compile your code. If you are adding your code to some other dll or to your own exe, you should define a different symbol; we suggest EXPCL_PANDASKEL, for instance, if you follow the example code shown in panda/src/skel (which I recommend following).

David

Thanks a lot, I’m checking config_xxx.cxx and skel files, Panda3D has sorprendent architecture, I’m really impressed :open_mouth:. Thanks again and good coding :slight_smile: