canvas

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Rigachupe
Citizen
Posts: 87
Joined: Fri Jun 18, 2021 11:21 am

canvas

Post by Rigachupe »

Learning to work with love.graphics canvas now. Is there a way i could copy a part of canvas?

For example the canvas is of size 1024x800. And i need a small rectangle of x=200,y=100,w=50,h=30 as something that will be worked on pixel level. That means set and get pixel functions.

Then i would need to draw that small part back onto the canvas at the same position and size i ripped out.

----
Normally i work with canvas like this:
- i have canvas 1024x800
- inside the love.update i get the image data
- i do the getPixel and setPixel onto the image data
- i then update the canvas with the image data (and this looks rather slow because the update takes the whole picture not just a small changed part)

Any way i could improve the speed? working on a small art painting program butt at 1024x800 size i see some slow down.
User avatar
dusoft
Party member
Posts: 551
Joined: Fri Nov 08, 2013 12:07 am
Location: Europe usually
Contact:

Re: canvas

Post by dusoft »

User avatar
marclurr
Party member
Posts: 121
Joined: Fri Apr 22, 2022 9:25 am

Re: canvas

Post by marclurr »

You should be able to use quads to render parts of the canvas somewhere else (e.g., to another canvas or the window). https://love2d.org/wiki/love.graphics.newQuad
User avatar
pgimeno
Party member
Posts: 3609
Joined: Sun Oct 18, 2015 2:58 pm

Re: canvas

Post by pgimeno »

For your use case I'd suggest an image instead of a canvas. You'd work with the image data and only transform it to an image for rendering purposes.

I wrote a PoC recently for something very similar: https://love2d.org/forums/viewtopic.php ... 38#p260038
RNavega
Party member
Posts: 299
Joined: Sun Aug 16, 2020 1:28 pm

Re: canvas

Post by RNavega »

I want to suggest yet another method. Since your goal is to make changes to the final canvas in the context of an art program, then I'd try drawing directly onto that canvas with the LÖVE drawing commands.
This would let you use brush stamps of different sizes (even down to just 1px), and no intermediary images/canvases would be necessary.

You can limit drawing to the offscreen canvas to a rectangular region by using love.graphics.setScissor().

This sounds like a very fun project btw. I studied a lot how to make an art program (it was supposed to be an animation sketching program), but lost interest.
Rigachupe
Citizen
Posts: 87
Joined: Fri Jun 18, 2021 11:21 am

Re: canvas

Post by Rigachupe »

Currently fighting with maybe a memory leak caused by creating new image from imagedata that i get through canvas:newImageData(). After changes made with pixels i make an new image love.graphics.newImage(imagedata) and draw it over canvas. It raises up to 14MB after while of work and then falls down to around 1.5MB. Hard to find the error.

Anyway you can try it here : https://tinyurl.com/2z6u562j
Rigachupe
Citizen
Posts: 87
Joined: Fri Jun 18, 2021 11:21 am

Re: canvas

Post by Rigachupe »

pgimeno wrote: Sun Jun 30, 2024 7:47 pm For your use case I'd suggest an image instead of a canvas. You'd work with the image data and only transform it to an image for rendering purposes.

I wrote a PoC recently for something very similar: https://love2d.org/forums/viewtopic.php ... 38#p260038
I should reconsider this option you suggested. Should work like this : https://www.love2d.org/wiki/(Image):replacePixels
Still i can not seem to find something that would update only a small part from that imagedata that has changed. Looking into the src code of sdl2 there is a method that can do this kind of task but it is not in the love API. The usual way i know from openGL is to
1. make a texture and get the unique ID
2. obtain the pixels from this texture
3. make some changes either all pixels or just part of that
4. use the opengl function to put all of the pixels or small rectangular part of the pixels back into the texture through the unique ID

So in this way it never needed to create a new texture or draw over it again with another texture.
RNavega
Party member
Posts: 299
Joined: Sun Aug 16, 2020 1:28 pm

Re: canvas

Post by RNavega »

In this code here, is it just on my system or when you release the mouse in the rectangular region (after drawing some points), the points drift slightly upwards?

Standalone main.lua:

Code: Select all

io.stdout:setvbuf('no')

table.clear = require('table.clear')
local tableInsert = table.insert


local POINTS_COLOR = {1.0, 1.0, 0.1}

local pointsTable
local isPainting
local myCanvas


function love.load()
    love.graphics.setDefaultFilter('nearest', 'nearest')
    myCanvas = love.graphics.newCanvas()
    love.graphics.setCanvas(myCanvas)
    local w, h = love.graphics.getDimensions()
    math.randomseed(os.time())
    local mr = math.random
    for x = 1, 100 do
        love.graphics.setColor(mr() * 0.5, mr() * 0.6, mr() * 0.6)
        love.graphics.circle('fill', w * mr(), h * mr(), 200.0 * mr(), 200.0 * mr())
    end
    love.graphics.setCanvas()
    love.graphics.setLineWidth(2.0)
    love.graphics.setLineStyle('rough')
    love.mouse.setVisible(false)

    isPainting = false
    pointsTable = {}
end


function love.draw()
    love.graphics.setColor(1, 1, 1)
    love.graphics.draw(myCanvas)

    love.graphics.setColor(0, 0, 0)
    love.graphics.rectangle('line', 200, 300, 300, 200)

    if isPainting then
        love.graphics.setScissor(200, 300, 300, 200)
        love.graphics.setColor(POINTS_COLOR)
        love.graphics.points(pointsTable)
        love.graphics.setScissor()
    end

    local mx, my = love.mouse.getPosition()
    if mx < 200 or mx > 200 + 300 or my < 300 or my > 300 + 200 then
        love.graphics.setColor(1, 0, 0)
    else
        love.graphics.setColor(1, 1, 1)
    end
    love.graphics.line(mx - 5, my, mx + 5, my)
    love.graphics.line(mx, my - 5, mx, my + 5)

    love.graphics.setColor(1, 1, 1)
    love.graphics.print('Painting: ' .. (isPainting and 'ON' or 'OFF'), 10, 10)
    love.graphics.print(('%d %d'):format(mx, my), 10, 30)
end


function love.keypressed(key)
    if key == 'escape' then
        love.event.quit()
    end
end


function love.mousemoved(mx, my)
    if isPainting then
        tableInsert(pointsTable, mx)
        tableInsert(pointsTable, my)
    end
end


function love.mousepressed(x, y, button)
    if button == 1 then
        isPainting = true
    end
end


function love.mousereleased(x, y, button)
    if button == 1 and isPainting then
        isPainting = false
        love.graphics.setColor(POINTS_COLOR)
        love.graphics.setCanvas(myCanvas)
        love.graphics.translate(0, 1)
        love.graphics.setScissor(200, 300, 300, 200)
        love.graphics.points(pointsTable)
        love.graphics.origin()
        love.graphics.setScissor()
        love.graphics.setCanvas()
        table.clear(pointsTable)
    end
end
While you're drawing (the mouse button is pressed), the points are drawn to the screen, but when you release the mouse they get 'committed' to the scratchpad canvas, and that's when the points / pixels shift up.
Last edited by RNavega on Wed Jul 03, 2024 10:14 pm, edited 1 time in total.
User avatar
pgimeno
Party member
Posts: 3609
Joined: Sun Oct 18, 2015 2:58 pm

Re: canvas

Post by pgimeno »

Rigachupe wrote: Tue Jul 02, 2024 6:59 pm Still i can not seem to find something that would update only a small part from that imagedata that has changed.
If you plan on using GL functions on the image (e.g. love.graphics.circle etc.) then you will need to read back these changes; otherwise your "original" can be the ImageData object, while the Image object would only be used for rendering.

If you really need to read back the result of using GL functions, then things get harder if you want to minimize the CPU<->GPU transfer size. The advantage of using only pixel manipulation on the ImageData is that there's one single CPU->GPU transfer and no CPU<-GPU one. The latter can be slow.

There is a function in ImageData, called ImageData:paste, which deals with copying rectangles from one ImageData to another. Not sure if that will be helpful in any way; I' don't know what you have planned.
RNavega
Party member
Posts: 299
Joined: Sun Aug 16, 2020 1:28 pm

Re: canvas

Post by RNavega »

RNavega wrote: Tue Jul 02, 2024 7:38 pm is it just on my system or when you release the mouse in the rectangular region (after drawing some points), the points drift slightly upwards?
Yeah they're drifting alright.
If when drawing to the canvas I temporarily love.graphics.translate() down one pixel, then everything looks correct. I edited the code with this fix.
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 3 guests