Page 1 of 2

AUTOMATIC QUAD DETECTOR

Posted: Sun Dec 19, 2021 4:52 am
by DebasishDatta
can someone please help with love2d function which can detect a quad from RPG sprite automatically. currently I am guessing the quad dimension and generating it with love.graphics.newQuad(). Please help me in this regard.

Re: AUTOMATIC QUAD DETECTOR

Posted: Sun Dec 19, 2021 4:05 pm
by darkfrei
How good is your spritesheet?
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
walk.png (25.37 KiB) Viewed 4799 times
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
run.png (21.78 KiB) Viewed 4799 times
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
https://www.gameart2d.com/cat-and-dog-free-sprites.html Creative Common Zero (CC0) a.k.a Public Domain license
jump.png (38.61 KiB) Viewed 4799 times
https://ezgif.com/sprite-cutter
Image
Image

Re: AUTOMATIC QUAD DETECTOR

Posted: Sun Dec 19, 2021 4:23 pm
by EngineerSmith
Why would you need to guess the size of your quads? They should all be equal in size to allow easy animation. Just count the width and height of the first frame and that's the size of that quad for that animation. You could write a meta file which holds this information for each file and have a system that reads that meta file to find how the size (You'd have to write the file though).

Unless your sprites are separate pngs then you can use a texture atlas packer like mine https://github.com/EngineerSmith/Export-TextureAtlas then you can add it to your build pipeline which packs all the sprites together and outputs a file with all the quad data to read in

Re: AUTOMATIC QUAD DETECTOR

Posted: Mon Dec 20, 2021 2:25 pm
by DebasishDatta
EngineerSmith , sorry to say , but I am not particularly clear with your explanation. For example, from your first picture how would you know what will be the size of the fist quad so that the figure of first cat fits in exactly.

Re: AUTOMATIC QUAD DETECTOR

Posted: Mon Dec 20, 2021 3:15 pm
by EngineerSmith
I'd open it in my picture editing software of choice and draw a shape over it or you can just make an educated guess: if the sprite sheet only contains one animation like those cats in top most picture each frame would be (10 frames / 380 pixels width)X(60 pixels height) : 38x60

Re: AUTOMATIC QUAD DETECTOR

Posted: Mon Dec 20, 2021 6:26 pm
by milon
DebasishDatta wrote: Sun Dec 19, 2021 4:52 am can someone please help with love2d function which can detect a quad from RPG sprite automatically. currently I am guessing the quad dimension and generating it with love.graphics.newQuad(). Please help me in this regard.
That depends entirely on how you index your quads. Personally, I index them as a one-dimensional table that I create when I load the image. You can index them differently, but you'll need to adapt my code to fit your style. Note that all code I'm about to post assumes there's a 1 pixel border between sprites, as recommended on the wiki to prevent bleeding when things get rotated or scaled.

This is the function I use to create quads for a given image:

Code: Select all

function newQuadsList(tileSize, width, height)
    local tilesX = (width - 1) / (tileSize + 1)
    local tilesY = (height - 1) / (tileSize + 1)
    local quadsList = {}
    for y = 1, tilesY do
        for x = 1, tilesX do
            quadsList[(y - 1) * tilesX + x] = love.graphics.newQuad((x - 1) * (tileSize + 1) + 1, (y - 1) * (tileSize + 1) + 1, tileSize, tileSize, width, height)
        end
    end
    return quadsList
end

I also wrote a tool to help me with exactly this same problem - finding the quad index number for a given sprite. Here it is! It assumes sprites are 32x32 pixels, but you can change that before running it. Just run it, then drag & drop your picture on it and mouse over the quad you want to know about. Use arrow keys to scroll the image and ESC to quit.

Code: Select all

-- Quad Finder
-- Helps determine a tile's position & quad number within its image
-- Assumes a 1px border between each tile!


-- User Input
local tiles = {w=32, h=32}  -- Size in pixels of tiles in image


-- Initialize
love.keyboard.setKeyRepeat(true)
image, mouse, screen = {}, {}, {}
screen.w, screen.h = love.graphics.getDimensions()
love.window.setMode(screen.w, screen.h, {resizable=true})
image.x, image.y, mouse.x, mouse.y = 0, 0, 0, 0
mouse.tile, mouse.tileX, mouse.tileY, image.file = "na", "na", "na", "na"
screen.foot = 35

function updateFooter()
    if image.img then
        screen.text = "Quad:"..mouse.tile.."   tile:"..mouse.tileX..","..mouse.tileY.."   mouse:"..mouse.x..","..mouse.y.."\nsize:"..image.w.."x"..image.h.."   file:"..image.file
    else
        screen.text = "Drag & drop a picture here!"
    end
end

function love.resize(w, h)
    screen.w, screen.h = w, h
end

function love.load()
    updateFooter()
end

function love.keypressed(key)
    if     key == "left"  or key == "a" and image.x < 0 then image.x = image.x + 10
    elseif key == "right" or key == "d" and image.x + image.w > screen.w then image.x = image.x - 10
    elseif key == "up"    or key == "w" and image.y < 0 then image.y = image.y + 10
    elseif key == "down"  or key == "s" and image.y + image.h > screen.h - screen.foot then image.y = image.y - 10
    elseif key == "escape" then love.event.quit()
    end
end

function love.filedropped(file)
    image.x, image.y = 0, 0
    if image.img then image.img:release(); image.img = nil end
    image.img = love.graphics.newImage(file)
    image.w, image.h = image.img:getDimensions()
    if type(file) ~= "string" then file = file:getFilename() end
    image.file = file
    image.tilesX = (image.w - 1) / (tiles.w + 1)
    image.tilesY = (image.h - 1) / (tiles.h + 1)
    assert(image.tilesX == math.floor(image.tilesX), "Incorrect image or tile size supplied!\nImage is "..image.w.."x"..image.h.."\nExpected tile size was "..tiles.w.."x"..tiles.h.."\nResulting image tile size: "..image.tilesX.." x "..image.tilesY)
    updateFooter()
end

function love.mousemoved(x, y, dx, dy)
    if not image.img then return end
    
    -- update x-axis
    mouse.x = x - image.x
    if mouse.x > image.w then
        mouse.tileX = "na"
    else
        mouse.tileX = mouse.x / (tiles.w + 1)
        if mouse.tileX == math.floor(mouse.tileX) then
            mouse.tileX = "na"
        else
            mouse.tileX = math.floor(mouse.tileX) + 1
        end
    end
    
    -- update y-axis
    mouse.y = y - image.y
    if mouse.y > image.h then
        mouse.tileY = "na"
    else
        mouse.tileY = mouse.y / (tiles.h + 1)
        if mouse.tileY == math.floor(mouse.tileY) then
            mouse.tileY = "na"
        else
            mouse.tileY = math.floor(mouse.tileY) + 1
        end
    end
    
    -- update hover tile
    if mouse.tileX == "na" or mouse.tileY == "na" then
        mouse.tile = "na"
    else
        mouse.tile = (mouse.tileY - 1) * image.tilesX + mouse.tileX
    end
    
    updateFooter()
end

function love.draw()
    if image.img then love.graphics.draw(image.img, image.x, image.y) end
    love.graphics.setColor(0, 0, 0)
    love.graphics.rectangle("fill", 0, screen.h - screen.foot, screen.w, screen.foot)
    love.graphics.setColor(1, 1, 1)
    love.graphics.print(screen.text, 10, screen.h - screen.foot + 3)
end

Re: AUTOMATIC QUAD DETECTOR

Posted: Tue Dec 21, 2021 4:18 am
by DebasishDatta
milon wrote: Mon Dec 20, 2021 6:26 pm
DebasishDatta wrote: Sun Dec 19, 2021 4:52 am can someone please help with love2d function which can detect a quad from RPG sprite automatically. currently I am guessing the quad dimension and generating it with love.graphics.newQuad(). Please help me in this regard.
That depends entirely on how you index your quads. Personally, I index them as a one-dimensional table that I create when I load the image. You can index them differently, but you'll need to adapt my code to fit your style. Note that all code I'm about to post assumes there's a 1 pixel border between sprites, as recommended on the wiki to prevent bleeding when things get rotated or scaled.

This is the function I use to create quads for a given image:

Code: Select all

function newQuadsList(tileSize, width, height)
    local tilesX = (width - 1) / (tileSize + 1)
    local tilesY = (height - 1) / (tileSize + 1)
    local quadsList = {}
    for y = 1, tilesY do
        for x = 1, tilesX do
            quadsList[(y - 1) * tilesX + x] = love.graphics.newQuad((x - 1) * (tileSize + 1) + 1, (y - 1) * (tileSize + 1) + 1, tileSize, tileSize, width, height)
        end
    end
    return quadsList
end

I also wrote a tool to help me with exactly this same problem - finding the quad index number for a given sprite. Here it is! It assumes sprites are 32x32 pixels, but you can change that before running it. Just run it, then drag & drop your picture on it and mouse over the quad you want to know about. Use arrow keys to scroll the image and ESC to quit.

Code: Select all

-- Quad Finder
-- Helps determine a tile's position & quad number within its image
-- Assumes a 1px border between each tile!


-- User Input
local tiles = {w=32, h=32}  -- Size in pixels of tiles in image


-- Initialize
love.keyboard.setKeyRepeat(true)
image, mouse, screen = {}, {}, {}
screen.w, screen.h = love.graphics.getDimensions()
love.window.setMode(screen.w, screen.h, {resizable=true})
image.x, image.y, mouse.x, mouse.y = 0, 0, 0, 0
mouse.tile, mouse.tileX, mouse.tileY, image.file = "na", "na", "na", "na"
screen.foot = 35

function updateFooter()
    if image.img then
        screen.text = "Quad:"..mouse.tile.."   tile:"..mouse.tileX..","..mouse.tileY.."   mouse:"..mouse.x..","..mouse.y.."\nsize:"..image.w.."x"..image.h.."   file:"..image.file
    else
        screen.text = "Drag & drop a picture here!"
    end
end

function love.resize(w, h)
    screen.w, screen.h = w, h
end

function love.load()
    updateFooter()
end

function love.keypressed(key)
    if     key == "left"  or key == "a" and image.x < 0 then image.x = image.x + 10
    elseif key == "right" or key == "d" and image.x + image.w > screen.w then image.x = image.x - 10
    elseif key == "up"    or key == "w" and image.y < 0 then image.y = image.y + 10
    elseif key == "down"  or key == "s" and image.y + image.h > screen.h - screen.foot then image.y = image.y - 10
    elseif key == "escape" then love.event.quit()
    end
end

function love.filedropped(file)
    image.x, image.y = 0, 0
    if image.img then image.img:release(); image.img = nil end
    image.img = love.graphics.newImage(file)
    image.w, image.h = image.img:getDimensions()
    if type(file) ~= "string" then file = file:getFilename() end
    image.file = file
    image.tilesX = (image.w - 1) / (tiles.w + 1)
    image.tilesY = (image.h - 1) / (tiles.h + 1)
    assert(image.tilesX == math.floor(image.tilesX), "Incorrect image or tile size supplied!\nImage is "..image.w.."x"..image.h.."\nExpected tile size was "..tiles.w.."x"..tiles.h.."\nResulting image tile size: "..image.tilesX.." x "..image.tilesY)
    updateFooter()
end

function love.mousemoved(x, y, dx, dy)
    if not image.img then return end
    
    -- update x-axis
    mouse.x = x - image.x
    if mouse.x > image.w then
        mouse.tileX = "na"
    else
        mouse.tileX = mouse.x / (tiles.w + 1)
        if mouse.tileX == math.floor(mouse.tileX) then
            mouse.tileX = "na"
        else
            mouse.tileX = math.floor(mouse.tileX) + 1
        end
    end
    
    -- update y-axis
    mouse.y = y - image.y
    if mouse.y > image.h then
        mouse.tileY = "na"
    else
        mouse.tileY = mouse.y / (tiles.h + 1)
        if mouse.tileY == math.floor(mouse.tileY) then
            mouse.tileY = "na"
        else
            mouse.tileY = math.floor(mouse.tileY) + 1
        end
    end
    
    -- update hover tile
    if mouse.tileX == "na" or mouse.tileY == "na" then
        mouse.tile = "na"
    else
        mouse.tile = (mouse.tileY - 1) * image.tilesX + mouse.tileX
    end
    
    updateFooter()
end

function love.draw()
    if image.img then love.graphics.draw(image.img, image.x, image.y) end
    love.graphics.setColor(0, 0, 0)
    love.graphics.rectangle("fill", 0, screen.h - screen.foot, screen.w, screen.foot)
    love.graphics.setColor(1, 1, 1)
    love.graphics.print(screen.text, 10, screen.h - screen.foot + 3)
end
That's very nice. Your code is a god one too. But if you know any function in love2d which can detect an optimum quad from an image file , that would be better, otherwise we have to manually fixed the image file first , then able to perform our operations e.g extracting quads etc.

Re: AUTOMATIC QUAD DETECTOR

Posted: Tue Dec 21, 2021 10:36 am
by dusoft
DebasishDatta wrote: Tue Dec 21, 2021 4:18 am That's very nice. Your code is a god one too. But if you know any function in love2d which can detect an optimum quad from an image file , that would be better, otherwise we have to manually fixed the image file first , then able to perform our operations e.g extracting quads etc.
There is nothing like that as previously said. You could however do background color pixel detection between quads, e.g. iterating over X axis and looking (approximating) for space between images. Once you find a pattern of repeated background color over certain intervals (e.g. each 33px is white, while 32px and 34px are colored and same applies for 65px etc.), you could split quads based on that. This requires some fuzzy detection work.

Re: AUTOMATIC QUAD DETECTOR

Posted: Tue Dec 21, 2021 12:21 pm
by Nikki
What are the tiles you are looking at? could you post an example?

Re: AUTOMATIC QUAD DETECTOR

Posted: Tue Dec 21, 2021 1:10 pm
by DebasishDatta
dusoft wrote: Tue Dec 21, 2021 10:36 am
DebasishDatta wrote: Tue Dec 21, 2021 4:18 am That's very nice. Your code is a god one too. But if you know any function in love2d which can detect an optimum quad from an image file , that would be better, otherwise we have to manually fixed the image file first , then able to perform our operations e.g extracting quads etc.
There is nothing like that as previously said. You could however do background color pixel detection between quads, e.g. iterating over X axis and looking (approximating) for space between images. Once you find a pattern of repeated background color over certain intervals (e.g. each 33px is white, while 32px and 34px are colored and same applies for 65px etc.), you could split quads based on that. This requires some fuzzy detection work.
Ok, thank you for your suggestion.