Harmony.codea - a procedural drawing tool

Okay, so to respond to various comments!

  1. You commented on my waiting .5s before “baking” the path. The choice is arbitrary, but I wanted to have some delay. I remember once coding an auto-save into a drawing program and if it triggered in the middle of a stroke then it would upset the drawing routine as it would cause a delay. Here, it could do something similar as the frame rate would suddenly drop. So I want to ensure that the user has definitely paused before baking the path. The choice of half a second comes from my touch library where touches form part of the same gesture if they occur within .5s of each other - think of a double or triple tap.

  2. Without a perfect line rendering system, there are going to be edge cases where the method produces less than perfect results. When the path is rendered with the alpha as it is constructed, it is easy to get undesirable artefacts from turning the corner too quickly or too slowly. Making the opacity of a path global instead of local is a standard method used in PDF and SVG so although it might not be what one would expect if you think of painting, it is what you expect if you come from a vector-based drawing system. However, as you pointed out, it is sometimes desirable to “bake” a path before it is finished so that the opacity is not global. It would seem to me to be very awkward to do that while having your finger still on the screen drawing the path and so lifting the finger, letting it “bake”, and then resuming the path seemed to me a reasonable solution. To make the path continuous, we need to join up the old and new paths - hence the “line” join method. So I disagree with your conclusion that it would be too tricky to use - to do this, you need to trigger something and that means either ending the current touch or starting another simultaneously. However, I concede that I’m hypothesising and I’ll need to test (and get others to test) to see what the best method is.

  3. The link between the “move” method and the baking is simply that so long as you wait .5s between the strokes, the first segment will have time to be baked.

  4. Yes, I need to sort out the orientation properly! The idea is to have the UI rotate but the drawing not do so. This is something I want in some other projects and I just need to sit down and work out the maths and the API. I suspect that I want something like transformViewport(desiredOrientation) which applies a transformation sufficient to transform the current orientation as if the iPad was in the desired orientation.

  5. I switched the Simple brush to BrushEx briefly because I was using it for debugging. I’ll switched it back.

Major change in the next version is the ability to draw with several touches at once. This took a fair bit of refactoring of the drawing routines so probably introduced a fair few new bugs. Haven’t looked at the one you mention above yet.

The ToolBox class is looking increasingly poorly named! I think I’ll rename it something more sensible.

Hmm. Still plenty of bugs.

Hi, good morning!

  1. Well, as I said some post ago I’ve implemented a baking version too and I’ve simply put the baking phase when the stroke ends. That’s usually not a real problem because long drops happens only if the number of vertices is very high, and that’s pretty difficult with the most of the brushes in a “normal” drawing session. The problem can arise very easily with circles or discs brushes but… well, I think it could be even useless to apply this solution to this brushes, because this type of brush doesn’t create unwanted or unexpected overlaps, but only overlaps that are part of the brush behavior. With your solution instead if I want to avoid all the line to be flattened I have to wait each time .5 sec before each new stroke and I found that pretty annoying while sketching. I’ve not put my baking code in the git repo because (as you see :slight_smile: ) I do not like it so much, so I’m still wondering about what to do with this functionality. Maybe adding it as optional could be the right solution. If you want I can share the code so you can have some tests.

  2. I agree with almost everything you say and it’s for that I’m thinking about introducing this functionality as an option. But I still don’t think that something like the line behaviour would be a good solution at the end because (and that’s just my opinion) I found more cons than pros. I’ve tried to sketch something with the line option on and most of the time that has led to unwanted lines (when I forgot to disable it) or anyway straight ones when I wanted just to continue a curve. But, again, it’s just my opinion :slight_smile:

  3. Ok, so with your solution you can draw several different strokes, with or without resetting the neighbour connection point alg after each stroke, and waiting or not the .5s you can decide how the overlapping areas will be threated. Well, I repeat myself: I found your current implementation very clever and powerfull, far far powerfull than original Harmony project. But as user I found it also a little unconfortable, it requires me to think too much while instead I’d like just to put the finger (or the pen) on the screen and draw, without esitation.

Anyway, I’m very happy to see how this project has involved you so much, also the multitouch is a really interesting extension and I’m very curious to see the results!

Now I’m working just to clean up and comment the code, to offer a little better interface (the aim is just to allow drawing fullscreen and I don’t care too much about using or not codea paramenter) and, most important, to add at least one level of undo/redo. The MeshCanvas already supports that now, I’ve just to work a little with the BrushEx class.

Ah, I’ve put a reference to you and to your version of the project in the readme of my github version, I hope that’s fine for you. I would also really like to give you credits on the project because even if we’ve developed very different code, the most of the ideas has come out discussing with you. I don’t think that we could have achieved the same results without this discussion. Do you know a correct way to give you credits for that in the license?

With your solution instead if I want to avoid all the line to be flattened I have to wait each time .5 sec before each new stroke and I found that pretty annoying while sketching.

It’s an easy enough fix. Just change the test if g.type.finished then to if g.type.ended.

But I still don’t think that something like the line behaviour would be a good solution at the end because (and that’s just my opinion) I found more cons than pros.

You wouldn’t invoke this functionality unless you knew what you were doing, so I find myself discounting your dislike of this! However, I will freely admit that it could be improved. How about making it last for a single “event”? So you turn it on if you want the next path that you will draw connect to the previous one, after which it reverts to the previous behaviour.

With undo/redo, how much are you thinking counts as a single “undo” step? The easiest would be the latest baked path. I guess you could have an array of canvas images corresponding to each baked path and you can undo/redo them by choosing which to display (probably optimise by writing the displayed ones to a single image).

With regard to licences, for me it is simple as I started with your code and adapted it so that’s pretty standard OS adaptation. For the reverse, I don’t know if there’s a standard way of crediting it. My experience is with scientific papers in which case one either goes for joint authorship (regardless of who actually typed the article) or puts an “acknowledgements” paragraph at the end of the introduction. Now that you’ve raised it, I’m curious as to the “standard practice” for this situation but shall not feel in any way slighted whatever you do: my code on this forum is (unless otherwise stated) PD and I fully realise what I’m giving away by doing that.

About undo/redo I just think to have each level linked to a single stroke. That would work correctly even with the baking logic if applied as soon as the stroke ends. Having a delayed baking logic that can group several strokes, instead, would require probably a different choice, and one level per baking phase seems to be a good one.

I’ve already implemented the undo/redo feature in a custom js harmony version and yes, the solution involved an array of images. But the real difficulties begin when you look at the brushes…

What about the list of previous points for brushes that derives from brushex, if resetBrushStartStroke (or move) is set to false? The easiest choice would be to just reset this list after an undo operation but… well, if you are drawing with that option set it could be not so fair.

Having just one level of undo should make things easier (and in fact that’s my taeget for now!) but I have to think to all the possibilities. Having multiple levels instead could lead to hard choices… or to very complex solutions that requires to have undo logic for almost everything, not just strokes!

About ‘line’… I agree, having an option to enable it only for a single stroke could be a good idea.

I like the ‘acknowledgements’ concept for the credits, that’s more or less what I’ve done putting the reference to this thread and to your project in the readme, maybe doing that in a little more formal way.

Right, I’ve put in a single level of undo - but just realised that it won’t work with remembering points.

I’ve also fixed the orientation stuff. If you rotate the iPad then the UI will rotate but the drawing won’t. This involves some snazzy stuff in the Library.

The join-by-line mode is a one-shot operator. It applies to the connection between the previous line and the next after which it reverts to whatever it was before.

Also new is a “Palm Rest” (in the library). And I’ve tracked down and squashed a nasty bug in the corner-turning code.

Look at this on Your iPad link: http://www.revoid.be/codebrush/

Or link: http://sketchpad.io/

What, exactly, am I looking for in those links? I tend not to click on random links unless given a reason to do so.

Latest version improves the undo/redo in that it takes into account the saved points as well. It does this by using self.count whenever working with the points table rather than table.insert or #self.points.

Also added the ability to put a picture on the background. The idea being that one could load a background picture and then “sketch” it by drawing on top. You can specify an opacity or tint to the background picture as well, and when you specify the picture you can also specify an orientation - not sure if my choice is the right way around here, nor if I have the LANDSCAPE_LEFT/LANDSCAPE_RIGHT the right way there. Maybe better would be to specify a transformation that is to be applied to the picture before rendering.

Wow, you’re leaving me behind! I’ve spent the last couple of days on another project and look how far have you gone! Really amazing the work you did, your version is day by day more similar to a professional drawing app based on harmony, like some you can find on web or also on iPad.

The import of a reference picture is a really good feature, I also had it in my custom harmony html5 version and it’s very usefull in a lot of situation.

I’d like to implement this type of things too, and also a save / load option to restart a drawing session, but… well, I really start to feel the need a good UI system, I can’t carry on relying just on codea parameters. And moreover I’m impressed to see how having a good and stable UI system helps you to add functionalities in a so short time! I could use you UI lib, that I’d like to study anyway, or start to implement one of my own. But I fear it could be a very long task…

Thanks!

What I’d really like would be the ability to take a picture with the camera and use that as the background, or provide a way for the user to select a picture from their photo library, but that needs extensions to Codea.

I wonder what information would be needed to save a picture. At the lowest level, one could just save the rendered image. At the highest level, one could save the points and the “style” in force at each point. Then at import one would quickly run through the points and generate the mesh and images. But to make a high-level save worth it, one would want something else to be able to read that format otherwise if this program is the only thing that can read it, may as well save the rendered image.

A possibility would be to provide an SVG export. That could be quite fun.

Oh, and I’m planning on writing an introduction to my UI library. For me, I’d be torn between the “using someone else’s work saves me time and effort” and “I never really understand something unless I write it myself”.

Yes please, I was giving a look to your code and even if it’s clear enough an introduction would be appreciated!

The integration with camera/photo library is indeed a great missing feature for Codea. For import the only good solution at now I think it could be the Dropbox integration. Moreover Dropbox sync should be bidirectional (I remember a thread speaking about that), so it should be possible also to export pictures this way, but that need further investigations.

Well, about saving my opinion is that saving / restoring an image would be enough. Expecialy with only one undo/redo level. Having instead a very large number of levels of undo/redo, storing also infos about different flags, colors, ecc… well, at that point it would be a pity do not save this infos as a project descriptor! And yes, the program should obviously offer an ‘export to img’ functionality. The best would be to add also the option to save a png with a transparent background!

Saving to image is simple: I’ve put a hide command in my UI which will leave just the drawing whereupon take a snapshot. Admittedly, this doesn’t handle the transparent background.

I felt that SVG was a reasonable halfway between a rendered fixed image and the raw data of the app. It wouldn’t be hard to bake an SVG at the same time as rendering the images. This has the advantage that its output is text-based so can at the least be saved to the project data.

Latest version has a Picture Browser for importing a background image. It can also be rotated/reflected to get it the right way up. Also, the resulting drawing (but not the background image and obviously not the UI) can be saved to the Documents sprite pack. I’ve also written instructions into the Main.lua tab for how to get your pictures from your photo library into Codea.

The order of drawing is:

  1. Background (white)
  2. Background image (can be tinted)
  3. Canvas background (can choose colour, including alpha)
  4. Existing paths
  5. Latest baked path (for undoing)
  6. Current path

So you can load an image and then put “tracing paper” over the top and trace over it.

I’m wondering what next to do with this! I feel quite happy with what’s there now (though no doubt there’ll be tweaks to how it works), but don’t really feel that it is complete. Maybe I’ll take a break and write about my library code first.

Oh, and the picture browser is in the library so you’ll need to update that as well.

In another project I had some code for rendering a bezier using meshes, and elsewhere again I’d done an implementation of Hobby’s algorithm to find a nice family of beziers passing through a given set of points.

I’ve been trying to merge these with this project to smooth out the main path as sometimes the touch data can be a little spaced out. But to no avail: there are too many points in the mesh and it takes too long to do all of the computation.

However, I figured out a simplified version of the algorithm and instead of triangulating then I simply split each curve into three pieces and draw lines. Result is still fast but gives smoother lines. Will upload new code over the weekend.

Library and Harmony code updated on my website.

Thanks for sharing this very nice project. It is a treasure trove for me. After playing around with Andrew_Stacey’s RoundRect function, I came up with a different type of color wheel. It might be something you can use, I don’t know. Anyway, here it is:

-- Main

function setup()

end

function draw()

    background(0, 0, 0)

    -- Stroke and fill must be the same
    pushMatrix()
    translate(HEIGHT/2, WIDTH/2)
    a = 600
    while a < 1080 do
        fill (a * 3 % 255, a * 5 % 255, a * 7 % 255)
        stroke (a * 3 % 255, a * 5 % 255, a * 7 % 255)
        pushMatrix()
        translate (100, 100)
        rotate(-(a * 2 % 360)) -- it just looks better rotated backwards
        roundRect(0, 0, 100, 22, 12.86)
        popMatrix()
        a = a + 10
        end
     popMatrix()
     fill(0, 0, 0, 255)
    stroke(0, 0, 0, 255)
    ellipse((WIDTH/2) + 110, (HEIGHT/2) + 90, 117) 
    fill(0, 0, 0, 0)
    strokeWidth(50)
    ellipse  ((WIDTH/2) + 110, (HEIGHT/2) + 90, 295)
     
end

-- ROUND RECT

function roundRect(x, y, w, h, r)

    pushStyle()
    insetPos = vec2(x+r,y+r)
    insetSize = vec2(w-2*r,h-2*r)

    rectMode(CORNER)
    rect(insetPos.x,insetPos.y,insetSize.x,insetSize.y)

    if r > 0 then
        smooth()
        lineCapMode(ROUND)
        strokeWidth(r*2)

        line(insetPos.x, insetPos.y, 
             insetPos.x + insetSize.x, insetPos.y)
        line(insetPos.x, insetPos.y,
             insetPos.x, insetPos.y + insetSize.y)
        line(insetPos.x, insetPos.y + insetSize.y,
             insetPos.x + insetSize.x, insetPos.y + insetSize.y)
        line(insetPos.x + insetSize.x, insetPos.y,
             insetPos.x + insetSize.x, insetPos.y + insetSize.y)            
    end
    popStyle()
end

```

I apologize for the poorly formatted posting of the above code. I can’t seem to make it look right. I also don’t know how to post a screen shot. By the way, I downloaded the latest Harmony and Library code, but there appears to be a problem. It looks as if the Brush class in the Harmony app has the experimental Bezier stuff in the strokeStart and basicStroke functions. In particular, it errors out when it calls the QuickHobby object (which I presume is in a different library and was used with the Bezier points). The old Brush class still works though.

Hi @Andrew_Stacey, I got back to work last week and we were in a very hard crunch time… moreover I have spent the few free time remaining on another small project so I’ve lost your latest updates. In lunch time I’m going to check your latest release to see the improvements, and I’m also so curious about the documentation/examples of your ui lib. ah, if you like, give a look to the original harmony js project or also to some derived projects, if I remember right there should be some interesting brushes based on bezier curves you could think to integrate! Ah, have you seen the post about comparison of performances of vec2 operations and lua number/math func operations? maybe move everything to vec2 wasn’t the best choice at the end!