Hello everyone 👋, hope everyone is having a good day.

Hopefully I am allowed to ask technical questions here, if not please tell me and I will remove this.

I am trying to create object oriented wrappers around `bindbc.sfml`, this is because I don't like the C-style syntax of CSFML.

The C-style syntax is not right -- in my opinion -- for an object oriented language. Dealing with pointers all the time is also unsafe.

This is not to say that CSFML isn't good -- it's great, and I've made some apps using `bindbc-sfml`. I just want to extend it to my liking with object oriented wrappers that can more closely match the C++ SFML syntax.

For the wrappers, I created a `Shape` class. This `Shape` class is seen in the original C++ SFML implementation:

```D
class Shape : Transformable, Drawable {
    void setTexture(sfTexture* texture, bool resetRect) {
        ptr.sfShape_setTexture(texture, resetRect);
    }

    void setTextureRect(IntRect rect) {
        ptr.sfShape_setTextureRect(rect.to_sfIntRect());
    }

    void setFillColor(Color color) {
        ptr.sfShape_setFillColor(color.to_sfColor());
    }

    void setOutlineColor(Color color) {
        ptr.sfShape_setOutlineColor(color.to_sfColor());
    }

    void setOutlineThickness(float thickness) {
        ptr.sfShape_setOutlineThickness(thickness);
    }

    const(sfTexture)* getTexture() {
        return ptr.sfShape_getTexture();
    }

    IntRect getTextureRect() {
        return ptr.sfShape_getTextureRect().toIntRect();
    }

    Color getFillColor() {
        return ptr.sfShape_getFillColor().toColor();
    }

    Color getOutlineColor() {
        return ptr.sfShape_getOutlineColor().toColor();
    }

    float getOutlineThickness() {
        return ptr.sfShape_getOutlineThickness();
    }

    size_t getPointCount() nothrow {
        return ptr.sfShape_getPointCount();
    }

    Vector2f getPoint(size_t index) nothrow {
        return ptr.sfShape_getPoint(index).toVector2f_noThrow();
    }

    FloatRect getLocalBounds() {
        return ptr.sfShape_getLocalBounds().toFloatRect();
    }

    FloatRect getGlobalBounds() {
        return ptr.sfShape_getGlobalBounds().toFloatRect();
    }

    private sfShape* ptr;
}
```

The `sfShape` pointer isn't currently initialized, I'll get to that issue soon.

As you can see, `Shape` extends the `Transformable` class and the `Drawable` interface. This again roughly matches what's seen in SFML. SFML.NET also did a similar wrapper for their CSFML C# bindings. What's great about SFML.NET is that you don't even know that you're using CSFML, this is because it feels just like C++ SFML.

Now, I will create a `RectangleShape` which will be a subclass of the `Shape` class:

(Btw I took a lot of inspiration from SFML.NET when it comes to these wrappers.)

```D
class RectangleShape : Shape {
    this(Vector2f size) {
        _size = size;
        setSize(_size);
    }

    Vector2f getSize() {
        return _size;
    }

    void setSize(Vector2f size) {
        _size = size;
    }

    override {
        size_t getPointCount() {
            return 4;
        }

        Vector2f getPoint(size_t index) {
            final switch (index) {
                case 0:
                    return Vector2f(0, 0);
                case 1:
                    return Vector2f(_size.x, 0);
                case 2:
                    return Vector2f(_size.x, _size.y);
                case 3:
                    return Vector2f(0, _size.y);
            }
        }
    }

    private Vector2f _size;
}
```

As you can see, the `Rectangle` class only overrides the `getPointCount` and `getPoint` methods.

**These are the methods that the superclass - `Shape` - will use to construct the shape object for it to actually be drawable.**

Now, let us add the following code to the `Shape` class so that we can construct a `Shape` via these two methods, which we assume that the child provides us a good implementation for:

```D
class Shape : Transformable, Drawable {
    this() {
ptr = sfShape_create(&getPointCount, &getPoint, cast(void*)this);
    }

extern(C) private static ulong getPointCount(void* data) nothrow {
        return (cast(Shape)data).getPointCount();
    }

extern(C) private static sfVector2f getPoint(size_t index, void* data) nothrow { return (cast(Shape)data).getPoint(index).to_sfVector2f_noThrow();
    }
```

I hear you asking, what's going on here?

We are providing two callbacks to the `getPointCount` and `getPoint` methods via function pointers, and we're passing in the current object to the `data` `void*` pointer. It's kind of hard to understand, but if you read through it carefully you should get a rough idea of what's going on.

Now, when we create a new instance of `Rectangle`, I will assume that the constructor will be called, the `sf_shape` ptr will be initialized correctly (as it will be utilizing the crucial `getPoint` and `getPointCount` methods) and everything will be OK.

This is the following test code I had:

```D
void main() {
        loadSFML();

RectangleShape rectangleShape = new RectangleShape(Vector2f(50, 50));
        rectangleShape.setPosition(Vector2f(50, 50));
        rectangleShape.setFillColor(Color.Blue);

RenderWindow renderWindow = new RenderWindow(sfVideoMode(500, 500), "Tests", sfWindowStyle.sfDefaultStyle, null);
        sfEvent event;

        while (renderWindow.isOpen()) {
                while (renderWindow.pollEvent(&event)) {
                        if (event.type == sfEventType.sfEvtClosed) {
                                renderWindow.close();
                        }
                }

                renderWindow.clear(Color.Yellow);
renderWindow.ptr.sfRenderWindow_drawShape(rectangleShape.ptr, null);
                renderWindow.display();
        }
}
```

I would read through this line by line to get a good idea of what's going on.

Really, for demonstration purposes, we're using the `renderWindow`'s `ptr` variable for drawing. When I can get this to work I will create wrapper functions so that it's nicer to use, but for now it's not important.

What I'd expect to pop up on screen is a 50x50 rectangle, filled with a blue color, at the position 50x50 on the screen.

Upon running the application, I don't see anything -- it's just a yellow screen.

I am very confused why this is the case, it seems like I've done everything fine, but I've obviously made a mistake somewhere in my implementation. I don't know specifically if it's an issue on my end, or a bug in `bindbc-sfml`, but this issue has infuriated me for days, because I am not getting what I expected to show up on screen :(

Any help with this would be greatly appreciated,

Regards,
thebluepandabear

Reply via email to