Godot: Get a pixel array from a draw_line method

Created on 8 Aug 2017  Â·  17Comments  Â·  Source: godotengine/godot

I've been playing with a little texture editor and managed to make a pretty quick and nifty draw method to draw freehand lines.

It uses the draw_line method to interpolate between points created by the mouse pointer

It's all fun and games until I try to commit the pixels to an image texture image, using the put_pixel() method.

That method needs an x and a y floating point for every pixel. So I need all the pixels from the draw_line method I used.

My strategy is to commit the pixels every time a new line is created- and only commit pixels of the last drawn line - upon mouse release.

I can't implement it unless I have the array of pixels created by a draw_line method.

I know I could use screen capture to do this, but it would be soo wasteful to screen cap the entire canvas

archived discussion

Most helpful comment

here is a proof of concept that you can draw using anything the engine provides:
ChalkBoard.zip
it's made in a hurry and not well aligned, but not very hard to improve to be a decent drawing app ;)

All 17 comments

One suggestion is to have draw_line() return the array of pixels it created. That would be extremely handy for then putting those pixels straight onto a sprite texture

example:
[Vector2(0,0),Vector2(10,10),Vector2(20,30),Vector2(50,800)]

right now it is a void and returns nothing

that's crazy inefficient, just implement a bresenham function

On Tue, Aug 8, 2017 at 8:59 AM, Todor Imreorov notifications@github.com
wrote:

One suggestion is to have draw_line() return the array of pixels it created

example:
[Vector2(0,0),Vector2(10,10),Vector2(20,30),Vector2(50,800)]

right now it is a void and returns nothing

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/10168#issuecomment-320934251,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AF-Z2_uvHaeoQveKYHcoaTB05_DIH8hrks5sWE2UgaJpZM4OwnlG
.

Somewhat related to #7727 (due to the original issue the OP had).

@reduz
Godot doesnt have a basenham function. Could that be added in the future, if it's a better approach?

Bresenham is fairly easy to implement though (you can probably do it yourself)

@Zireael07 It would be quite handy to have it if it helps with that issue. Could be used in other creative ways :)
I didnt know about basenham before stumbling on this

Bresenham does is used a lot, especially in 2D

@Zireael07 @reduz Bresenham doesnt however account for line thickness and color

While it would be useful to have, wouldnt it be even better if we had a method to draw lines straight into images

right now we can only put single pixels like this:
editableImage.put_pixel(pixel.x,pixel.y, color)
This is super limited and results in a spray paint tool at best

my suggestion is to add a draw line method to the image class that works like put pixel, but instead puts all the pixels of a line
example:
editableImage.draw_line(start,end,color,width)

That would directly hit the issue and make it much much easier to implement a lightweight sprite editor within godot

While being on the subject, is it possible to store a draw buffer and write it to an image, without having to resolve to screen capturing?
What is the best way to do this with godot's available methods?

Commit a freehand stroke made with a draw_line draw() function to an image

I need this in order to implement an eraser tool later on

Right now I am storing all of my strokes in an array - which kind of makes it hard further down

should I be drawing a polygon on top of the brasenham in order to get the thickness implemented?
https://stackoverflow.com/questions/1222713/how-do-i-create-a-line-of-arbitrary-thickness-using-bresenham

@blurymind: I implemented bresenham in GDScript and getting it to accept color was fairly easy. Thickness is more difficult however, especially for angled lines.

I might try erasing pixels in the draw event instead and save to texture when saving to file only. Seems simpler

its just having to store all those lines in an array is wildly inefficient - it would be better to save them to a texture instead - every time i release the mouse cursor

Why not draw on a render texture instead of pixel per pixel in GDScript? You got a whole rendering engine dedicated to do just that.

@Zylann can you provide an example :)
@reduz @Zireael07 is it possible to erase pixels in the draw() method?

Right now when I want to create a freehand stroke, I record Vector2 coordinates point array while the mouse is down and then draw lines between the points

I am storing all of my lines in an array.

Basically what I am wondering now is - how do I erase pixels?
Obviously I need to commit the pixels I created in my draw function to somewhere , rather than storing all of the lines and their points in an array structure and re-render it on each draw

So If I commit it to a texture, what I am wondering is how do I then erase pixels from that texture with a freehand stroke? Do I draw lines with zero alpha on them - to replace normal lines with alpha? What blending mode to use? Mix? Can I re-use my freehand line drawing function to also erase pixels?

How do I write to a texture from what was made in the draw() function? Do I screen capture to a sprite?
I am thinking of giving this a try later:
http://docs.godotengine.org/en/stable/learning/features/viewports/viewports.html

here is a proof of concept that you can draw using anything the engine provides:
ChalkBoard.zip
it's made in a hurry and not well aligned, but not very hard to improve to be a decent drawing app ;)

@Zylann Thank you :)
While I appreciate your example and it is showing me some new things about the nodes,such as
viewport.set_render_target_clear_on_new_frame(false)

It still doesnt have a way of erasing pixels, when I set the brush to a transparent pixels color with another event - that doesnt overwrite the existing pixels with transparent ones

It's not doing anything that my current implementation is not already doing, apart of the accumulation of pixels that doesnt now require arrays to store the lines and re-render them

How do you write to the alpha channel of existing pixels - replace alpha :O

I would replace
board.set_pos(Vector2(200,200))
with
board.set_centered(false)
:)

I think you need to post a more focused issue about "how to blend alpha like other colors" with drawing functions. It is unusual, but your use case shows that it can be needed in texture drawing. The only workaround I can think of is to use a second texture as an alpha buffer, and use it as a mask with a shader to make pixels disappear on the main board.

@Zylann You are right, I started this issue with another request.
I will file a new issue for erasing pixels in the draw method
https://github.com/godotengine/godot/issues/10255

I am closing this issue, since the approach to solve this problem wasnt right to begin with.

The discussion about erasing pixels has moved here:
https://github.com/godotengine/godot/issues/10255

Was this page helpful?
0 / 5 - 0 ratings