Transfer one buffered image to another.

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
oscaradalid
Prole
Posts: 11
Joined: Wed May 09, 2018 11:48 am

Transfer one buffered image to another.

Post by oscaradalid »

Good morning, I have made this code, what I do is transfer the tile image to the background using the buffer, the problem is that I find it still quite slow. I have done it in javascript, without external libraries and it is much better applying this technique. How can I optimize the code to gain more frames – another thing. GetData doesn't work anymore?

Code: Select all

-- Lista de nombres de tiles disponibles
local tileNames = {"tile-000.png", "tile-001.png"}

-- Variables globales para la imagen de fondo y sus datos, así como para la imagen de tile
local fondo
local fondoData

local tile
local tileWidth, tileHeight = 16, 16
local a1Speed = 1
local a1Direction = 1
local a1Position = 0
local distanciaRecorrida = 0

-- Variable para almacenar los FPS
local fps = 0

function love.load()
  -- Cargar imagen de fondo (a1)
  fondo = love.graphics.newImage("a1.png")
  fondo:setFilter("nearest", "nearest")

  -- Crear ImageData para la imagen de fondo
  fondoData = love.image.newImageData("a1.png")

  -- Cargar imagen de tile aleatoria
  seleccionarTileAleatorio()
end

function love.update(dt)
  -- Actualizar posición de a1
  a1Position = a1Position + a1Speed * a1Direction

  -- Verificar si a1 ha avanzado 16 píxeles
  distanciaRecorrida = distanciaRecorrida + a1Speed
  if distanciaRecorrida >= 16 then
    -- Cambiar dirección
    a1Direction = -a1Direction

    -- Pegar el tile en 16 posiciones aleatorias
    for i = 1, 4000 do
      local x = love.math.random(0, 320 - tileWidth * 4)
      local y = love.math.random(0, 240 - tileHeight * 4)
      pegarTileEnFondo(x, y)
    end

    -- Reiniciar la distancia recorrida
    distanciaRecorrida = 0

    -- Seleccionar un nuevo tile aleatorio
    seleccionarTileAleatorio()
  end

  -- Actualizar los FPS
  fps = love.timer.getFPS()
end

function love.draw()
  -- Dibujar la imagen de fondo a1
  love.graphics.draw(fondo, a1Position, 0, 0, 4, 4)

  -- Dibujar los FPS en la esquina superior izquierda
  love.graphics.print("FPS: " .. fps, 10, 10)
end

function pegarTileEnFondo(x, y)
  -- Crear ImageData para el tile actual
  local tileData = love.image.newImageData(tile)

  -- Copiar los píxeles de la nueva imagen a la ImageData principal
  for i = 0, tileWidth - 1 do
    for j = 0, tileHeight - 1 do
      local r, g, b, a = tileData:getPixel(i, j)
      fondoData:setPixel(x + i, y + j, r, g, b, a)
    end
  end

  -- Actualizar la imagen de fondo con los nuevos datos
  fondo = love.graphics.newImage(fondoData)
end

function seleccionarTileAleatorio()
  -- Seleccionar un nombre de tile aleatorio de la lista
  tile = tileNames[love.math.random(1, #tileNames)]
end



RNavega
Party member
Posts: 251
Joined: Sun Aug 16, 2020 1:28 pm

Re: Transfer one buffered image to another.

Post by RNavega »

Hi. Before saying anything, do you have more info on what you're trying to do, like screenshots or sketches etc? Anything that would explain what end result you're after.
Also, are you planning on saving the resulting background image onto disk, like to a PNG image file, or is that image just supposed to be displayed on screen during the game and then discarded when the user leaves the game?
BurrickSlayer
Prole
Posts: 15
Joined: Sat Dec 21, 2013 4:28 pm

Re: Transfer one buffered image to another.

Post by BurrickSlayer »

My Spanish isn't the best, so I'm not really sure what you would like to achieve here. But maybe a SpriteBatch (https://love2d.org/wiki/SpriteBatch) is what you're looking for?
oscaradalid
Prole
Posts: 11
Joined: Wed May 09, 2018 11:48 am

Re: Transfer one buffered image to another.

Post by oscaradalid »

I'm doing tests on how to assemble my scroll engine, maybe someone will use this piece of code that has cost me all afternoon to get it out, it's not my thing to program.Put two 800x300 background1 and background2 images in the root carpant and then two 16x16 images

Code: Select all


local fondo1
local fondo2
local fondoData1
local fondoData2
local tileImage
local tileCanvas
local tileX, tileY

local scrollSpeed1 = 600
local scrollSpeed2 = 800
local offsetX1 = 0
local offsetX2 = 0
local fps = 0

-- Crear ImageQuad para la repetición de fondos
local fondoQuad1
local fondoQuad2

function love.load()
  local windowWidth, windowHeight = love.graphics.getWidth(), love.graphics.getHeight()

  fondoData1 = love.image.newImageData("fondo1.png")
  fondoData2 = love.image.newImageData("fondo2.png")

  fondo1 = love.graphics.newImage(fondoData1)
  fondo1:setFilter("nearest", "nearest")

  fondo2 = love.graphics.newImage(fondoData2)
  fondo2:setFilter("nearest", "nearest")

  tileImage = love.graphics.newImage("tile-000.png")
  tileImage:setFilter("nearest", "nearest")

  tileCanvas = love.graphics.newCanvas(tileImage:getWidth(), tileImage:getHeight())

  tileX = (windowWidth - tileImage:getWidth()) / 2
  tileY = (windowHeight - tileImage:getHeight()) / 2

  -- Crear Quad para repetición de fondo1
  fondoQuad1 = love.graphics.newQuad(0, 0, fondo1:getWidth(), fondo1:getHeight(), fondo1:getDimensions())

  -- Crear Quad para repetición de fondo2
  fondoQuad2 = love.graphics.newQuad(0, 0, fondo2:getWidth(), fondo2:getHeight(), fondo2:getDimensions())
end

function love.update(dt)
  fps = love.timer.getFPS()

  offsetX1 = offsetX1 + scrollSpeed1 * dt
  offsetX2 = offsetX2 + scrollSpeed2 * dt

  -- Hacer que offsetX1 y offsetX2 estén dentro de los límites de la imagen de fondo
  offsetX1 = offsetX1 % fondo1:getWidth()
  offsetX2 = offsetX2 % fondo2:getWidth()

  local x1 = love.math.random(0, love.graphics.getWidth() - tileImage:getWidth())
  local y1 = love.math.random(0, love.graphics.getHeight() - tileImage:getHeight())

  local x2 = love.math.random(0, love.graphics.getWidth() - tileImage:getWidth())
  local y2 = love.math.random(0, love.graphics.getHeight() - tileImage:getHeight())

  -- Limpiar el contenido del tileCanvas antes de cada operación
  love.graphics.setCanvas(tileCanvas)
  love.graphics.clear()

  pegarTileEnFondo(x1, y1, fondoData1, offsetX1)
  pegarTileEnFondo(x1, y1, fondoData1, offsetX1 + fondo1:getWidth())

  pegarTileEnFondo(x2, y2, fondoData2, offsetX2)

  -- Reemplazar píxeles solo cuando sea necesario
  fondo1 = love.graphics.newImage(fondoData1)
  fondo2 = love.graphics.newImage(fondoData2)
end

function love.draw()
  love.graphics.clear()

  -- Dibujar fondo1 repetido a 300 pixeles en el eje y
  for i = math.floor(-offsetX1), love.graphics.getWidth(), fondo1:getWidth() do
    love.graphics.draw(fondo1, fondoQuad1, i, 300)
  end

  -- Dibujar fondo2 repetido
  for i = math.floor(-offsetX2), love.graphics.getWidth(), fondo2:getWidth() do
    love.graphics.draw(fondo2, fondoQuad2, i, 0)
  end

  love.graphics.print("FPS: " .. fps, 10, 10)
end

function pegarTileEnFondo(x, y, fondoData, offsetX)
  love.graphics.draw(tileImage, 0, 0)
  love.graphics.setCanvas()

  local tileImageData = tileCanvas:newImageData()
  fondoData:paste(tileImageData, x + offsetX, y, 0, 0, tileImage:getWidth(), tileImage:getHeight())
end

User avatar
knorke
Party member
Posts: 239
Joined: Wed Jul 14, 2010 7:06 pm
Contact:

Re: Transfer one buffered image to another.

Post by knorke »

I only quickly scrolled through your code, it seems you call newImage multiple times per frame. That is slow.
RNavega
Party member
Posts: 251
Joined: Sun Aug 16, 2020 1:28 pm

Re: Transfer one buffered image to another.

Post by RNavega »

I'm still not sure what you're trying to do. In your first code you used manual CPU-side pixel copying, now you're using the Canvas objects (which will greatly improve on speed as it'll use the GPU instead), but neither are being used in a way that couldn't already be done by drawing the contents directly to the screen, instead of these intermediary buffers.

If you want a scrolling tile background, then you don't need to use a canvas: the game screen can be composited in real-time inside the love.draw() function by drawing all tiles to screen, using a scrolling offset.
Then you draw other elements after that so they are layered on top of what's already on screen.
Post Reply

Who is online

Users browsing this forum: No registered users and 62 guests