1. Anders Ruud
  2. love
  3. Issues

Issues

Issue #678 wontfix

Different functions for filled and outlined shapes

hahawoo
created an issue

There are two issues with how things are at the moment:

  • The draw mode for shapes has to be specified all the time.
  • The draw mode is mixed in with the conceptually distinct geometry information, except with lines.

My proposal to fix these is to have different functions for filled and outlined shapes:

love.graphics.arc( x, y, radius, angle1, angle2, segments )
love.graphics.arcLine( x, y, radius, angle1, angle2, segments )
love.graphics.circle( x, y, radius, segments )
love.graphics.circleLine( x, y, radius, segments )
love.graphics.rectangle( x, y, width, height )
love.graphics.rectangleLine( x, y, width, height )
love.graphics.polygon( vertices )
love.graphics.polygonLine( vertices )
love.graphics.line( points )

Additional benefits are:

  • There are less characters to type.
  • It avoids the use of an enum. Using an enum, you have to be aware of what other values the enum can have. Here, the information is in the function name.
  • Consistency of some sort. To the best of my knowledge, no other function which takes an argument to change the "style" of the function has such an argument without a default. (See love.audio.newSource, Source:seek, love.filesystem.newFileData, etc.)

The only drawback I can see is that there are simply more functions. But, I think they result in a net decrease of complexity.

Comments (10)

  1. criptych

    I've used APIs with a similar convention and rather liked it. What about using "drawX" and "fillX" for lines and fills, respectively? This would echo the generic "draw" function and match the use of verbs as function names throughout most of LOVE.

    If I'm not mistaken, dropping the enum may also help performance, but only slightly.

  2. hahawoo reporter

    That's cool that it's used successfully elsewhere. And it's an interesting observation about verbs as function names, I hadn't thought of that.

    An issue with drawX and fillX though might be that fillX functions would be the only functions which drew something to the screen and didn't start with draw (Edit: Actually that's not right, print and printf don't start with draw either). I guess it could be drawFilledX, but that's getting a bit too long. Alternatively it could be drawX and drawXLine. But I'm still a fan of X and XLine, just because I like the primitives being concise.

  3. kikito

    If we ever went this route, I would vote to name the functions 'strokeXXX' and 'fillXXX' respectively. Stroke and fill are common verbs on drawing APIs.

  4. hahawoo reporter

    The problem I see with strokeShape and fillShape is that the verbs don't really say what they do, for example strokeCircle doesn't "stroke a circle". Well... maybe it does? I dunno, just seems slightly strange to me at the moment.

    drawStrokedCircle or drawOutlinedCircle or drawCircleLine seem to say what they do more accurately, I think, maybe, to me.

    The word "stroke" and verbs (stroke/fillShape) are inconsistent with love.graphics.line, which uses the word "line" and is a noun. I guess strokeLine would be possible?

    I'm still a fan of the nouns shape and shapeLine though. It's a good point that most LÖVE functions are verbs, but to note, not all are:

    love.graphics.origin
    love.math.noise
    love.math.random
    love.math.randomNormal
    love.filesystem.lines
    

    They could be made into verbs though:

    love.graphics.goToOrigin -- Something better than this. :D
    love.math.generateNoise
    love.math.generateRandom
    love.math.generateRandomNormal
    love.filesystem.iterateLines
    

    Still, I'm not sure whether this consistency would be worth it.

  5. hahawoo reporter

    Or...

    love.graphics.draw
    love.graphics.drawText
    love.graphics.drawTextWrapped
    love.graphics.drawArc
    love.graphics.drawArcLine
    love.graphics.drawCircle
    love.graphics.drawCircleLine
    love.graphics.drawRectangle
    love.graphics.drawRectangleLine
    love.graphics.drawPolygon
    love.graphics.drawPolygonLine
    love.graphics.drawLine
    

    To quote from Bret Victor's Learnable Programming:

    This example assumed a hypothetical graphics library which was designed for autocomplete -- all of the drawing functions begin with "draw", so the completion list would appear as the designer intended.*

    * Strangely, I don't actually know of any APIs that are intentionally designed with autocomplete in mind. I do know many APIs, such as Processing, that are designed for brevity, which is irrelevant in an environment with good autocomplete.

    If this is a good idea, then maybe something like this is too:

    love.graphics.coordPop
    love.graphics.coordPush
    love.graphics.coordRotate
    love.graphics.coordScale
    love.graphics.coordShear
    love.graphics.coordTranslate
    
  6. Bart van Strien

    If we were to go for stroke/fill functions: The different shapes take different arguments, so the list of arguments will be annoying to document, and annoying to remember. At the moment it's easy to remember circle takes a centre and a radius, and a polygon takes points, with fill it'd take both, depending on the value of the first argument.

    Wrt splitting them up even more, so strokeCircle, etc, that doesn't have the earlier problem, but it does mean doubling all the functions for, in my opinion, questionable benefit. And if ever a third mode were to be added, that would duplicate all primitive drawing functions again, where they all describe the same behaviour. As it is, it selects a behaviour within a shape, rather than a different shape.

    And regarding "autocomplete-targeted" APIs, the biggest downside of that is that, yes, it may make using autocomplete-using IDEs easier to use, it, pretty much by definition, makes non-autocomplete-based editing harder. Now, it wouldn't even be that bad if autocomplete was very accurate and common for lua, but it isn't.

  7. criptych

    Just kind of throwing this out there, but how about a third option? Use single function for each shape, but split setColor into setFillColor and setStrokeColor (perhaps the original function sets both?). Then each shape function draws both fill and stroke, unless the respective color is set to nil. This "avoids the use of an enum" without greatly increasing the number of functions, and could help performance a little in cases where you draw a lot of shapes both filled and stroked (esp. for circle/ellipse as only half the calculations are needed).

  8. Alex Szpakowski

    I think Processing does that, and I'm not a fan of it - especially because it introduces even more global state that users have to be aware of and deal with every single time they call a shape drawing function.

    It also doesn't mix well with my intent to add separate Shape and Line batch objects (which would mainly be separate for implementation reasons).

  9. criptych

    I'm not a fan of it - especially because it introduces even more global state

    Hmm. It wasn't my favorite idea, either, in fact I originally thought to add the colors as parameters to the shape functions instead. But that poses its own problems, like making setColor kind of useless (although I suppose it would play nicer with batch objects); and all but requiring a new Color type, or else the new signature would be pretty unwieldy: e.g. love.graphics.arc(x, y, radius, angle1, angle2, segments, fillR, fillG, fillB, fillA, lineR, lineG, lineB, lineA).

  10. Log in to comment