Page 1 of 1

How to create "darker" version of image?

Posted: Tue Apr 09, 2019 4:19 pm
by Bizun
Hi, I'm new and I don’t know if my code is optimal for "shadowing" sprites.

Code: Select all

local sprites = {
  ['@'] = { drawable = nil, dark = nil, fname = 'hero.png' },
  ['.'] = { drawable = nil, dark = nil, fname = 'ground.png' },
  ['#'] = { drawable = nil, dark = nil, fname = 'wall.png' },
  ['f'] = { drawable = nil, dark = nil, fname = 'fungus.png' },
  ['F'] = { drawable = nil, dark = nil, fname = 'fungus-big.png' },
  ['>'] = { drawable = nil, dark = nil, fname = 'stairs-down.png' },
  ['<'] = { drawable = nil, dark = nil, fname = 'stairs-up.png' },
  ['b'] = { drawable = nil, dark = nil, fname = 'bat.png' },
}

local SpriteRenderer = class('SpriteRenderer')

-- ...

function SpriteRenderer:load()
  for index, value in pairs(sprites) do
    local image = love.graphics.newImage('data/' .. sprites[index].fname) -- load image
    image:setFilter('nearest', 'nearest')
    sprites[index].drawable = image
    
    -- making "shadowed" copy
    sprites[index].dark = love.graphics.newCanvas(self.spriteWidth, self.spriteHeight)
    love.graphics.setCanvas(sprites[index].dark)
      love.graphics.clear()
      love.graphics.setColor(1, 1, 1, 1)
      love.graphics.draw(image, 0, 0)
      love.graphics.setColor(0, 0, 0, 0.5)
      love.graphics.rectangle('fill', 0, 0, self.spriteWidth, self.spriteHeight)
    love.graphics.setCanvas()
  end
end

-- ...

function SpriteRenderer:draw(char, x, y, isDark)
  local w = self:getSpriteWidth()
  local h = self:getSpriteHeight()
  if isDark then
    love.graphics.draw(sprites[char].dark, x * w, y * h) -- using darker copy
  else
    love.graphics.draw(sprites[char].drawable, x * w, y * h)
  end
end
Is correct use of canvas? Maybe i need use something other? Thanks!

P.S. Code is correctly create darkerk copy of sprites, but im not sure in correctly using of canvas.

Re: How to create "darker" version of image?

Posted: Tue Apr 09, 2019 6:43 pm
by zorg
One subjectively better option would be to use ImageData instead of Image, create regular images from that, then modify the imagedata with the mapPixel method so that each pixel gets darkened by a simple formula, and create images from those as well; here's the modified minimal code:

Code: Select all

function SpriteRenderer:load()
  for index, value in pairs(sprites) do
    local image = love.graphics.newImageData('data/' .. sprites[index].fname) -- load image
    -- make "regular" image
    sprites[index].drawable = love.graphics.newImage(image)
    sprites[index].drawable:setFilter('nearest', 'nearest')
    
    -- making "shadowed" copy
    image:mapPixel(function(x,y,r,g,b,a) return r*.2, g*.2, b*.2, a end) -- or use a variable to store the darkening amount
    sprites[index].dark = love.graphics.newImage(image)
    sprites[index].dark:setFilter('nearest', 'nearest')
  end
end

Re: How to create "darker" version of image?

Posted: Tue Apr 09, 2019 10:52 pm
by raidho36
To-go way of doing it is simply creating multiple versions of your sprites, artistically adjusted to perfect visual effect. You'd usually resort to programmatic image adjustment if the manual approach was out of the question (dynamic nature of effect or far too many colors to implement). And at that, I'd recommend using shader-based coloring; default shader lets you darken the sprite color by setting the drawing color.

Re: How to create "darker" version of image?

Posted: Wed Apr 10, 2019 4:30 am
by ivan
Your code looks fine in theory but drawing a black rectangle over the image might look incorrect if the texture is partially transparent. You could just use "setColor(0.5,0.5,0.5,1)" for the particular image.