Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Implementable Drawable class  (Read 2077 times)

0 Members and 1 Guest are viewing this topic.

pdinklag

  • Sr. Member
  • ****
  • Posts: 330
  • JSFML Developer
    • View Profile
    • JSFML Website
Implementable Drawable class
« on: August 14, 2012, 09:44:45 pm »
Currently, JSFML lacks a way of implementing custom drawables. By that, I mean that there is no Drawable interface that declares a drawing method that can be implemented in pure Java and that defines how an object is drawn. It can, of course, be done by writing a draw method that takes a RenderTarget as an argument and will proceed to draw to it, but this practically inverts the common SFML semantics of RenderTarget.draw(Drawable) and is therefore not ideal.

The question is how to do it properly. Currently, org.jsfml.graphics.Drawable is a basic interface without any method definitions, the main reason for this being the private access of the draw method in sf::Drawable implementations. Therefore, my solution proposal is as follows:

For JSFML (which uses its own set of SFML headers), modify the draw methods of the stock sf::Drawable implementations to be public. This is the simplest of ways and there should not be any real drawback. Nobody will use the JSFML headers for writing SFML applications in C++, so this would break SFML's design for JSFML's internals only.

In RenderWindow and RenderTexture, the draw methods would no longer be implemented natively, but delegate to the draw method of the respective Drawable on a Java level,  which then is delegated to native code, ie exactly like SFML does this itself (except it has access to the protected method). This would result in a single Drawable interface that is implemented natively for the native SFML classes and can be equally used by custom implementations. This would also fix another serious problem that currently exists in the JSFML API: the Drawable interface has to be public, but currently it must not be implemented by anything that is not an SFMLNativeObject and passed to RenderTarget.draw, because it assumes an underlying SFML object.

I'm open to other solutions, of course. I don't really like to touch the SFML headers in any way, but on the other hand, this is a minor change with a huge benefit for the binding.
JSFML - The Java binding to SFML.

pdinklag

  • Sr. Member
  • ****
  • Posts: 330
  • JSFML Developer
    • View Profile
    • JSFML Website
Re: Implementable Drawable class
« Reply #1 on: August 15, 2012, 07:35:50 am »
On a second thought, there is a simpler way: make the native implementation of a Drawable's draw method simply use the standard SFML mechanism. :)

However, trying to do this leads me to another problem:
The "RenderTarget" is passed to the Drawable's draw method as the first parameter. Now, RenderTarget is an abstract class / interface. In the Java object, I store the pointer to the native SFML object as a long integer value and I statically cast it back to a given pointer type like so:
jlong ptr = (...) //fetch from Java object
(sf::RenderWindow*)ptr
(where jlong is a typedef to a signed 64-bit integer)

The problem: I can not use this to cast the pointer to an abstract type like sf::RenderTarget, because the vtable pointer will still point to the vtable of the implementing class, in this case either sf::RenderTexture or sf::RenderWindow. Dynamic casting is not possible, because at compile time I do not have any type information except for the long int. I also do not know of any way to store type information in C++.

The only thing I can imagine that could work is, for abstract types, to define another pointer to be stored in the Java object that points to the same object cast up to the abstract type, and provide another method to retrieve that pointer. This would be possible in the object's construction chain, although it's certainly not pretty.
JSFML - The Java binding to SFML.

pdinklag

  • Sr. Member
  • ****
  • Posts: 330
  • JSFML Developer
    • View Profile
    • JSFML Website
Re: Implementable Drawable class
« Reply #2 on: August 15, 2012, 05:10:46 pm »
Done!
A simple example of what's possible now is the following, a text with a shadow:
public class ShadowText extends Text {
    private Color shadowColor = new Color(Color.BLACK, 128);
    private Vector2f shadowOffset = new Vector2f(3, 3);

    public ShadowText() {
    }

    public ShadowText(@NotNull String string, @NotNull Font font) {
        super(string, font);
    }

    public ShadowText(@NotNull String string, @NotNull Font font, int characterSize) {
        super(string, font, characterSize);
    }

    public void setShadowAlpha(int alpha) {
        this.shadowColor.setAlpha(alpha);
    }

    public void setShadowOffset(Vector2f shadowOffset) {
        this.shadowOffset = shadowOffset;
    }

    @Override
    public void draw(@NotNull RenderTarget target, @NotNull RenderStates states) {
        Color color = getColor();
        Vector2f pos = getPosition();

        //Shadow
        setPosition(pos.x + shadowOffset.x, pos.y + shadowOffset.y);
        setColor(shadowColor);
        super.draw(target, states);

        //Text
        setPosition(pos);
        setColor(color);
        super.draw(target, states);
    }
}
JSFML - The Java binding to SFML.

 

anything