0 votes

I'm overriding the Node2D.draw() method so that I can draw some custom images in my node. However, my attempt to build an image from pixels is failing. I am setting the pixels of my image to different colors, but when I call the draw_texture() method, it's as if my image contains only white. What am I doing wrong?

func _draw():
    var bg = Image.new();
    bg.create(100, 100, false, Image.FORMAT_RGBA8);
    bg.lock();

    for j in range(100):
        for i in range(100):
            bg.set_pixel(i, j, Color(
                float(i) / 100.0,
                float(j) / 100.0,
                0.0,
                1.0
            ));

    bg.unlock();
    bg.generate_mipmaps();

    var bgTex = ImageTexture.new();
    bgTex.create_from_image(bg);

    draw_texture(bgTex, Vector2(0.0, 0.0))
asked Jul 27 in Engine by kitfox (90 points)
edited Jul 27 by kitfox

Looks like this fails if I try and do it in the _draw() callback. However, if I use a Sprite and build the ImageTexture in _ready() or _process(delta) and assign the result to my Icon's texture variable, it displays properly.

2 Answers

+1 vote
Best answer

For performance reasons the execution time of CanvasItem rendering is not done at the same time as other things in script. This isn't documented very well, but it is also the reason why you can only use the draw functions in the _draw() function or when signaled/notified.

If I'm remembering correctly, what happens in your code is that the draw_texture is going to take place slightly after this function. So the GDScript function finishes first and the scoped variables are cleared off the stack and the contents are no longer available.

It's not very intuitive, and not ideal, but you can work around it in the way you mentioned, but more specifically by lifting the variable you're using to a higher scope. Then it will be alive and well for the visual server's reference later.

IE - As seen like the first line I added to your code below:

var bgTex : ImageTexture # <--- Lift var to this scope.

func _draw():

    var bg = Image.new();
    bg.create(100, 100, false, Image.FORMAT_RGBA8);
    bg.lock();

    for j in range(100):
        for i in range(100):
            bg.set_pixel(i, j, Color(
                float(i) / 100.0,
                float(j) / 100.0,
                0.0,
                1.0
            ));

    bg.unlock();
    bg.generate_mipmaps();

    bgTex = ImageTexture.new();
    bgTex.create_from_image(bg);

    draw_texture(bgTex, Vector2(0.0, 0.0))
answered Jul 28 by avencherus (4,831 points)
selected Jul 28 by kitfox
0 votes

Aren't you using print() or printt() to output your variables' contents to the debugging window? There you could display each created pixel's color and check whether the generated values are as expected.

answered Jul 28 by ChristianSF (72 points)

I was checking for that in the debugger window. The Image was being built correctly- it was creating the ImageTexture that was failing. I'm guessing the _draw() method is called on a different thread which prevents the ImageTexture from being built.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.