Create a custom Array in gdextension

Godot Version

Godot 4.2

Question

Hi, I’m working on interfacing opencv with Godot.
And one thing that comes up a lot is std::vectors of data, points etc.

So naturally I’d like to just access those with Godot as an array.

My idea is to inherit array and, provide my own functions that use an underlying vector instead of the default ones.

But I’m unsure how I could do this.

I think, there must be a way to tell ClassDB that there is just another array type, right?

Yea follow the GD extension guide

I’m not sure I completely follow what you said but Godot array is a vector under the hood. I suspect you may need a base type like an int16 or something. Whatever it is you can make it with gd extension and hook up all the bindings for GD script use. Then once your type is registered I think you get the typed array for free. Array[my new type]

thanks,
first of all let me be clear, my goal was to implement opencv interface for godot, so that more people are able to use it, since the library is pretty good and allows a lot of AR/CV functionality.

but after digging trough godots code, two things became clear.

  1. godot-cpp has no support for operators, or extending gdscript built in types
  2. there’s NO documentation, what so ever.

I was gonna go into detail on how maybe you could re-implement array, or send a different method to function pointers in the gdextension interface.

But it all really boils down to, godot-cpp and gdscript have small to no interoperability, and what is and what isn’t possible isn’t even described anywhere.
There Is an issue talking about this that is 2 years old https://github.com/godotengine/godot-docs/issues/5618

in the responses, some people try to defend the fact that it’s fine to not have documentation, and that “all it takes is dedication”.

Which is incredibly frustrating.
Over all my experience with godot has been: “features coming soon and documentation later, after those are done”

Seeing the state of things, I’m at a point where I can do one of few things really:

  • Make my own gdscript implementation, which would allow me to have greater control over it’s internals and allow me to implement things in a way that is more usable.

  • Make an engine plugin, that would allow me more direct control over godots internals, and by extent gdscript

  • give up on gdscript completely, and switch to C# and just use C# natively

  • go find a different, more documented, engine

It is open source software with a team of 10 paid individuals with 5k+ issues on GitHub and multiple supported branches.

What is the use of GDExtensionPtrOperatorEvaluator in core/extension/gdextension_interface.h ?

(Sorry I haven’t had the time to fully read the code)

1 Like

Np!
I’ve looked at it briefly and it seems to take pointers to variants, do math on them and return them as another pointer.

Breakdown after following references:

GDExtensionPtrOperatorEvaluator->
Variant::get_ptr_operator_evaluator
Which containts ptr_operator_evaluator_table
Which takes an instance from T::ptr_table with T being class template

And looking for an example of that, in variant_op.h
It uses PtrToArg::convert on two parameters, calls an operator like pow or /, etc… and then PtrToArg::encode on the return value.

Looking the other way out, from godot-cpp this gets registered using bind method and then gets called from your extension whenever you call an operator like / or ==

So it’s the opposite of what I’m looking for lol, calling the operator implementation in Godot it self.

but if you have any other ideas I’m open to go trough them, like I really want to make this work!

1 Like

I was on the godot-proposals, typing in the proposal to have a custom array or ITERABLE type.

And then I tried googling godot custom iterators, that’s IT!!!,
Godot has custom iterators!!! IT WAS THERE, THE WHOLE TIME!

now the question still stands if this is portable between GDscript and GDextension, I hope that it is since it seems to be just methods in the variant class, but I need to try it first to see if it actually works, if so I’ll post an answer with example code!

(if this works, this is going to be the biggest “couldn’t see the python for all the c++” solution ever)

One part of the solution, Iterator code:
Mind you not the best way to iterate over a vector BUT IT WORKS!

However, while this makes things nicer and easier, it still doesn’t let me do operator[idx] for now this seems to be only doable from variant type, which atm cannot be overriden.

Maybe there is a way to make godot think that a class is type Variant::VARIANT as well but by default objects are type Variant::OBJECT


class CV_vectorKeypoint : public RefCounted
{
GDCLASS(CV_vectorKeypoint, RefCounted)

private:
    int i = 0;

public:
    std::vector<cv::KeyPoint> contents;

public:

    CV_vectorKeypoint()
    {}

    Ref<CV_KeyPoint> getAt(int index)
    {
        Ref<CV_KeyPoint> ref;
        ref.instantiate();
        ref->hidden = contents[index];
        return ref;
    }

    void setAt(int index, Ref<CV_KeyPoint> value)
    {
        contents[index] = value->hidden;
    }

    int64_t getSize()
    {
        return contents.size();
    }
    
    Variant _iter_init(const Variant &p_iter)
    {
        i = 0;

        if (contents.size() == 0)
        {
            return false;
        }

        return true;
    }

    Variant _iter_next(const Variant &p_iter)
    {
        i++;
        if (i < contents.size())
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    Variant _iter_get(const Variant &p_iter)
    {
        return getAt(i);
    }

protected:
    static void _bind_methods()
    {
        
        ClassDB::bind_method(D_METHOD("getAt", "index"), &CV_vectorKeypoint::getAt);
        ClassDB::bind_method(D_METHOD("setAt", "index", "value"), &CV_vectorKeypoint::setAt);
        ClassDB::bind_method(D_METHOD("getSize"), &CV_vectorKeypoint::getSize);

        ClassDB::bind_method(D_METHOD("_iter_init", "v"), &CV_vectorKeypoint::_iter_init);
        ClassDB::bind_method(D_METHOD("_iter_next", "v"), &CV_vectorKeypoint::_iter_next);
        ClassDB::bind_method(D_METHOD("_iter_get", "v"), &CV_vectorKeypoint::_iter_get);
    }
};
1 Like

When I was looking at how variant (built-in) types did their operators I found that they were all hard coded. It would seem to me that it wouldn’t be as easy as GDextension to add a new built-in.

I will say that I would avoid trying to do heavy computation in gdscript. In turn creating handles to resources that can be orchestrated and passed to various binded OpenCV functions. (and maybe could be passed internally?)

(I profiled array sum in GDscript with a large number of elements, it took around ~120s with as many optimisations I could think of, where native c++ only took ~5s)

I don’t know the complete data model of OpenCV, and if the image class of Godot and other built in types can suffice for the basic stuff.

I found out that I did once talk to some other about OpenCV, maybe they could give some advice.

Good luck!

1 Like

Thanks for all the help!

Yeah I’m thinking of doing just high level stuff kinda like numpy in python, but the lack of operator overloading makes it hard, the top level code will look like mess.

I think, the best thing to do is to make my own version of gdscript, that would turn special names into operators, or would allow me to choose between core code and my own code.
Kinda like how gdscript is doing with iterators now.

I’ll also be able to flex and use my knowledge on compilers and high performance code :3c

I’ll definitely share the finished product on the forums once it’s done!

1 Like