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

Author Topic: Make CircleShape, RectangleShape, and ConvexShape only be shapes. Not drawables.  (Read 17256 times)

0 Members and 1 Guest are viewing this topic.

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
I dont like that idea, because it is really backwards. Currently Sprite is there to be the simplest possible thing to be drawn, where it just puts a texture on screen as it is (often with a 1:1 mapping of texels to pixels), with the textures alpha determining the perceived shape.
The Shape classes are for complicated uses, can have any number of vertices determining the draw area and have outlines with a different color. Bloating the Sprite class with all kinds of rarely used extraneous functionality will result in loosing the simple class that is probably used more often and complicating that usecase.

I would think if a change is done its more useful to add the possibility of putting all Drawables into a VertexArray or Batch class and only then actually drawing everything at once. Maybe direct drawing could then even be removed to simplify porting to modern OpenGL using VBOs.

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
And as always in designing an API, let's not focus on technical details ("A is assigned a B", "I don't like if X no longer inherits Y")... It makes no sense to discuss at them as long as we're not clear what functionality is actually desired.
Yes and no. Example: some people here are confused (IMO) and think that you would not be able to create a sprite without having to create an additional resource (shape). And that's not necessarily true if your API is well defined. So you need to explain at least *a bit* the API to show how it could work. But otherwise you're right: defining a precise API now would be premature.

Anyway, about features. What could be interesting to investigate is a mix of texture and shape where a sprite would be a basic construct (class, factory, ...) based on this general idea to simply display a rectangle texture, while the more general construct could handle simple shapes, or custom ones provided by the user, without mandatory texture. On top of that we can manage border thickness, border color, fill color and all the properties we currently have.

How shape are defined is another interesting question. Would it be whole shapes or sequences of connected segments? Something different?
SFML / OS X developer

Critkeeper

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
The biggest argument against this that I can see is having to create a shape in order to create a sprite, and how managing an additional asset for every sprite that would annoy some people. You could make the default behaviour exactly the same as it is now, that is that sprites use rectangular shapes, by using a C++ feature called implicit conversion.

Just make a single parameter constructor for rectangle shape, for example a vec2d giving its dimensions.

Then if you want to build a sprite shape but you specify a vec2d instead of an actual shape, c++ will implicitly convert it to a rectangle shape before passing it through the constructor. Notice we don't actually have to overload the constructor or anything like that.

We didn't tell the constructor that a vec2d is a valid parameter, but c++ doesn't care. You don't have to write any additional code in the library, and if you later change your mind about the type of the single argument that is passed to single argument constructors for various shapes, then you don't have to rewrite any code.

http://stackoverflow.com/questions/121162/what-does-the-explicit-keyword-in-c-mean (read the first answer)

If you try to make single argument constructors to other shapes, like a circle for example, specifying its radius, then this technique will work just the same.

What happens when you try to specify a single argument constructor whose argument shares a type that you've already covered, like an ellipse whose constructor takes a single argument sf::vec2d, I don't really know but I would expect a compiler error because of ambiguity.
« Last Edit: December 10, 2014, 01:04:52 pm by Critkeeper »
if(CritKeeper.askQuestion()){return question.why();}

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
The biggest argument against this that I can see is having to create a shape in order to create a sprite, and how managing an additional asset for every sprite that would annoy some people. You could make the default behaviour exactly the same as it is now, that is that sprites use rectangular shapes, by using a C++ feature called implicit conversion.
It all depends if the sprite owns the shape or not. If it does own the shape then you don't need an extra asset. (That's why I've been trying to say for a while but apparently failed to do so.)

Let's assume a sprite has its own shape. Then, by default, a sprite creates a rectangle shape. If told otherwise (e.g. with an explicit shape as constructor parameter or through factory methods) then it will copy this shape for its own usage. In both cases we don't have to keep track of this shape ourselves.

On the other hand, if it does *not* own the shape then we need to keep it alive long enough, like the texture. But I think it doesn't make sense to go that way: a shape is not that heavy (unlike the texture) and don't live on the GPU (also unlike the texture) so we can copy it a few times without trouble.
SFML / OS X developer

Critkeeper

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
The biggest argument against this that I can see is having to create a shape in order to create a sprite, and how managing an additional asset for every sprite that would annoy some people. You could make the default behaviour exactly the same as it is now, that is that sprites use rectangular shapes, by using a C++ feature called implicit conversion.
It all depends if the sprite owns the shape or not. If it does own the shape then you don't need an extra asset. (That's why I've been trying to say for a while but apparently failed to do so.)

Let's assume a sprite has its own shape. Then, by default, a sprite creates a rectangle shape. If told otherwise (e.g. with an explicit shape as constructor parameter or through factory methods) then it will copy this shape for its own usage. In both cases we don't have to keep track of this shape ourselves.

On the other hand, if it does *not* own the shape then we need to keep it alive long enough, like the texture. But I think it doesn't make sense to go that way: a shape is not that heavy (unlike the texture) and don't live on the GPU (also unlike the texture) so we can copy it a few times without trouble.

Oh yes I was agreeing with you.

I'm just saying that you have people who want to be able to make a sprite without bothering with shapes, and you have people that do want to bother with it.

Most people would implement your idea by setting the shape to be the last argument given in the constructor for the sprite class, and then giving it a default value equal to an arbitrary rectangle like a unit square. (ugly because we are stuck with a default size for the rectangle)

Or they would provide a a "shape selector" parameter (ugly because we are stuck with a "default" version, like a unit circle or unit rectangle)

Or they would make it so that sprite is unusable even after it is constructed until a factor method is used to set the shape (very bad implementation imho).

All of those implementations have things wrong with them that people could argue over.


What I'm saying is you can get around that with a nifty feature of C++ that allows you to just specify the argument in the constructor of the sprite to be of the same type of the argument that constructs the shape-- but only if the shape can be built from one single argument. And whats nifty about it is you don't have to write any code. C++ just says "Oh gee I don't know how to build a sprite out of a vec2d or a float, but I know how to build it out of a shape, and I know how to build a circle out of a float and I know how to build a rectangle out of a vec2d, and circles and rectangles are both shapes, so I'll just use the right one."

Furthermore the sprite can have multiple arguments. It will substitute the right argument in the right place. You could write in the definition of sprite that it should take an argument shape, an argument color, and an argument position, and you automatically get atleast 2 constructors out of that "magically". Namely, the one that happens if I provide a float instead of a shape, and it gets turned into a circle, and the one that happens when I provide a vec2d instead of a shape, and it gets turned into a rectangle.

In other words there is no need to have a single "default shape". With this we get a default rectangle and a default circle (and a default w/e, one for each shape that can be built from a single unique parameter) and not only that, we don't have to settle for a "unit" rectangle or "unit" circle or whatever. We can specify the dimensions at the constructor and it will know what we meant, because there is no ambiguity. And it costs us nothing because we don't have to write more constructor code.
« Last Edit: December 10, 2014, 01:48:51 pm by Critkeeper »
if(CritKeeper.askQuestion()){return question.why();}

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
You're approach is too specific IMO. As Nexus said we should try to think about functionality.

If I understood you correctly you want to use some kind of Prototype Patter Design. For me, it's way to complicated to generate a shape. You don't need to do all that to get a bon unit rectangle: Notice how I said "by default, a sprite creates a rectangle shape" and not "the default value is a rectangle". We can achieve that with two constructors: One with a shape parameter and one without (and thus building the default rectangle according to some other data like the texture). We can of course have more than two ctors.

Since you're interested in the topic, what's a shape for you?
SFML / OS X developer

Critkeeper

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
You're approach is too specific IMO. As Nexus said we should try to think about functionality.

If I understood you correctly you want to use some kind of Prototype Patter Design. For me, it's way to complicated to generate a shape. You don't need to do all that to get a bon unit rectangle: Notice how I said "by default, a sprite creates a rectangle shape" and not "the default value is a rectangle". We can achieve that with two constructors: One with a shape parameter and one without (and thus building the default rectangle according to some other data like the texture). We can of course have more than two ctors.

Since you're interested in the topic, what's a shape for you?

You aren't quite understanding me. I'm saying we don't have to pass a shape to the constructor of the sprite to get a default rectangle, we can just pass a vec2d instead. And I'm saying we don't have to write a brand new constructor that has a vec2d as a parameter because C++ will automatically turn a vec2d into a rectangle, even without us writing any code to tell it how to do that, and it will use that.


A shape is a set of vertices connected by lines in a specific order such that the first and last vertices are connected. If the first and last vertices aren't connected then all we have is a set of connected lines that approximates a curve. If there isn't a specific order then the only way we can uniquely assign lines is if the number of vertices is equal to 2, which is a degenerate case and the definition of a line.

Therefore as far as I'm concerned, a shape has 3 or more vertices, the same number of lines, and the vertices are ordered.

It is fine if perimeter of the shape intersects with itself. The numeral 8 would be a shape for example.

In short, a shape is a special kind of curve, such that the first and last vertex are connected.
« Last Edit: December 11, 2014, 01:37:07 am by Critkeeper »
if(CritKeeper.askQuestion()){return question.why();}

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
I wouldn't call this questionable use of implicit conversion a feature. A constructor taking sf::Vector2f for rectangles is not any less tedious than one taking the rectangle shape. Plus, special treatment for rectangles is confusing. If you want to keep things simple, do it like now -- infer the size from the texture.

And as mentioned earlier by me and again by Hiura, before thinking about concrete constructor overloads, you should be clear about the general relationship between shapes and sprites. Does a sprite have a shape? Does it refer to one? How does the shape interact with the texture? Etc...
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Humm I went indeed a bit too fast on your vec2d thing. Sorry about that - got a lot on my mind right now.

But you still gives something to the ctor to build the shape, right? So you also have the problem of size not automatically matching the texture (if any) or did I missed something else? In either case we might want that the size is explicitly set (or not -- this is just a morning thought ^^).

Anyway, that's an interesting idea but I'm not sure implicit conversations are appropriate here. I would have to think a bit more about it. It would be probably easier to get the whole picture later since this is more or less an implementation detail.

I do like your definition of shape though. I feel it covers pretty much everything we need.

However we have to investigate more how we handle line thickness: With a circle,it's very easy (take two consecutive points, find the middle point, add a normal vector of the wanted length and you got one point of the "other" circle that make it fat) but for others like rectangle it's not that easy.

Have you (guys) think about it yet?
SFML / OS X developer

Critkeeper

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
And as mentioned earlier by me and again by Hiura, before thinking about concrete constructor overloads, you should be clear about the general relationship between shapes and sprites. Does a sprite have a shape? Does it refer to one? How does the shape interact with the texture? Etc...
  • Vertex:
    • A vertex has a position.
    • A vertex has a color.
  • Curve:
    • A curve has an ordered set of vertexes.
    • Every successive pair are connected by lines.
    • The color of the lines is a gradient from one vertex to the other based on the color of the vertex. (this can be done directly with opengl)
    • Curve inherits from drawable.
  • Shape:
    • A shape has curve.
    • The first and last vertex in the set are connected.
    • A shape's fill color is gradient from any one vertex to any other vertex based on the vertex colors. (this can be done directly with opengl)
  • Sprite:
    • A sprite has a shape. If none is provided it will be inferred from the texture as a rectangle.
    • A sprite must have a texture.
    • The texture replaces the fill color of the shape and the texture is clipped by the perimeter of the shape.
    • If later someone figures that they want the texture to be distorted rather than clipped to the shape, then implementing that into later versions of sfml can be a possibility.
    • You might be able to use the vertex color information for distortion constants or whatever

This is an example of what vertex blended fill colors looks like:


In case you are wondering about performance, vertex blending is a fundamental graphics operation implemented in hardware for almost every GPU in the past 10 years, so there isn't going to be a performance penalty.
« Last Edit: December 11, 2014, 08:47:36 am by Critkeeper »
if(CritKeeper.askQuestion()){return question.why();}

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Quote
A sprite may or may not have a texture.

Wouldn't a sprite with no texture be identical to whatever the default shape for sprites is? (eg, a white square)

Critkeeper

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Quote
A sprite may or may not have a texture.

Wouldn't a sprite with no texture be identical to whatever the default shape for sprites is? (eg, a white square)

Yeah sorry I rethought that at the last moment. It doesn't make sense for a sprite to not have a texture, because then it would literally be identical to a shape.

That means that a sprite MUST have a texture.

I also put in an additional clause that makes it so that if no shape is given to the sprite, a rectangle will be inferred from the texture.
« Last Edit: December 11, 2014, 08:48:08 am by Critkeeper »
if(CritKeeper.askQuestion()){return question.why();}

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Well, this all depends on whether shapes are drawable or not.. if they are not, and I think that the point of this discussion, then a sprite can have no texture.
SFML / OS X developer

mashedtatoes

  • Newbie
  • *
  • Posts: 23
    • View Profile
Oooh. Lots of discussion since I last checked this thread.
Quote
Well, this all depends on whether shapes are drawable or not.. if they are not, and I think that the point of this discussion, then a sprite can have no texture.
Yup, that is definitely a main point. The less clear, but I think the more important, request is that a sprites shape should function as a clipping mask.