Quads, sprites and coordinate systems

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
target.san
Prole
Posts: 8
Joined: Thu Apr 05, 2012 6:41 pm

Quads, sprites and coordinate systems

Post by target.san » Sun Feb 25, 2018 9:51 pm

Hello,

Making my first steps in Love2D, I tried to make simple top-down maze walker.
What I hit very quickly were some specifics of engine's rendering coordinate systems.
In particular, I tried to change default draw coordinate system such that width or height of one square tile is exactly 1 unit. Nothing too hard.
Next I tried to use quads to render tiles. What really surprised me is that both quad mesh's dimensions and its "on-screen" dimensions influence texture coordinates. While I thought that first 4 parameters to newQuad influence only texture coordinates, pixel-wise, and based on images' dimensions.

To sum up, it appears that Love2D is intended to work with pixel-based coordinate and rendering systems, while it seems to not have affine matrix math included in its standard library.

What I'd like to know is what's the usual way of implementing games where level coordinate system doesn't match draw coordinate system?

User avatar
pgimeno
Party member
Posts: 1500
Joined: Sun Oct 18, 2015 2:58 pm

Re: Quads, sprites and coordinate systems

Post by pgimeno » Sun Feb 25, 2018 10:14 pm

I can't reproduce the effect you're experiencing. Can you give an example?

This works just fine for me:

Code: Select all

local lg = love.graphics
-- this image is 256x256 and has 4 parts
local img = lg.newImage('2x2.png')
local q1 = lg.newQuad(  0,   0,   128, 128,   256, 256)
local q2 = lg.newQuad(128,   0,   128, 128,   256, 256)
local q3 = lg.newQuad(  0, 128,   128, 128,   256, 256)
local q4 = lg.newQuad(128, 128,   128, 128,   256, 256)

function love.draw()
  love.graphics.scale(0.2, 0.2)
  love.graphics.draw(img, q1)
end
It draws a small version of the first sprite, as expected. What you can't do is define quads in your own units. You need the image dimensions in pixels to define a quad, but not to use it.
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

target.san
Prole
Posts: 8
Joined: Thu Apr 05, 2012 6:41 pm

Re: Quads, sprites and coordinate systems

Post by target.san » Mon Feb 26, 2018 10:38 am

Hi,

Thanks for your response

I'm trying to do something opposite:

Code: Select all

c_unitPixels = 64
-- Scene transformation and scale applied each frame
g_sceneTrans = { 0, 0 }
g_sceneScale = { 0, 0 }

function love.resize(wx, wy)
    -- Recalculate scene coordinate system
    g_sceneTrans[1] = wx / 2
    g_sceneTrans[2] = wy / 2
    g_sceneScale[1] =  c_unitPixels
    g_sceneScale[2] = -c_unitPixels
end

function love.load()
    love.resize(love.graphics.getWidth(), love.graphics.getHeight())
    texture = love.graphics.newImage('16x16.png')
    -- 1. Unexpectedly gets desired result
    quad = love.graphics.newQuad(0, 0, 1, 1, 1, 1)
    -- 2. Sprite goes off-screen, textured part is of desired size, the rest looks like stretching of borders
    -- I expected it will work as expected
    -- quad = love.graphics.newQuad(0, 0, texture:getWidth(), texture:getHeight(), 1, 1)
    -- 3. Sprite is properly textured, but stretched beyond screen
    -- quad = love.graphics.newQuad(0, 0, texture:getWidth(), texture:getHeight(), texture:getWidth(), texture:getHeight())
    -- 4. Sprite is of proper size, but contains single pixel
    -- quad = love.graphics.newQuad(0, 0, 1, 1, texture:getWidth(), texture:getHeight())
end

function love.draw()
    local g = love.graphics
    -- First, transform coordinate system such that
    -- Y goes up, zero is at screen center and dimensions are in tiles, not pixels
    g.translate(g_sceneTrans[1], g_sceneTrans[2])
    g.scale(g_sceneScale[1], g_sceneScale[2])
    -- Actual drawing goes here
    g.setColor(255, 255, 255)
    g.draw(texture, quad, 0, 0)
end
I got already that quads aren't intended for use with "abstract scene units". And the only option I see is to define meshes manually, possibly over texture atlas.

User avatar
pgimeno
Party member
Posts: 1500
Joined: Sun Oct 18, 2015 2:58 pm

Re: Quads, sprites and coordinate systems

Post by pgimeno » Mon Feb 26, 2018 11:11 am

Ah, got it. So you're expecting it to keep its original size when scaled. That's not what scaling does; scaling zooms everything.

The "standard" approach for most uses is your number (3) above, where you say "Sprite is properly textured, but stretched beyond screen"; to compensate for the stretching, you can do this:

Code: Select all

g.draw(texture, quad, 0, 0, 0, 1/g_sceneScale[1], 1/g_sceneScale[2])
An alternative is to multiply the coordinates at render time:

Code: Select all

function love.draw()
    local g = love.graphics
    -- First, transform coordinate system such that
    -- Y goes up, zero is at screen center and dimensions are in tiles, not pixels
    g.translate(g_sceneTrans[1], g_sceneTrans[2])
    -- Actual drawing goes here
    g.setColor(255, 255, 255)
    g.draw(texture, quad, 0 * g_sceneScale[1], 0 * g_sceneScale[2])
end
But you can also use your approach (1). If you define "width" and "height" in basic units (of size 64x64 pixels in your case) and count the number of sprites, you can work like that. In the above example, you say you're using a 16x16 image but your coordinates are 64x64, therefore the correct width and height of the image should be 16/64 = 0.25.

Example: you have a sprite sheet of 512x512 pixels, each sprite being 64x64, and your base square is 64x64. You would create a quad with width and height 8, 8 and the quads would be at integral coordinates, like this:

Code: Select all

  local i = 1
  for y = 0, 7 do
    fox x = 0, 7 do
      quads[i] = love.graphics.newQuad(x, y, 1, 1, 8, 8)
      i = i + 1
    end
  end
Or alternatively:

Code: Select all

  local myUnit = 64
  local width, height = img:getDimensions()
  local i = 1
  for y = 0, width - 1, myUnit do
    fox x = 0, height - 1, myUnit do
      quads[i] = love.graphics.newQuad(x / myUnit, y / myUnit, 1, 1, width / myUnit, height / myUnit)
      i = i + 1
    end
  end
Since you invert the Y axis, you may need to flip the sprite and use this instead:

Code: Select all

      quads[i] = love.graphics.newQuad(x / myUnit, (y + myUnit - 1) / myUnit, 1, -1, width / myUnit, height / myUnit)
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

target.san
Prole
Posts: 8
Joined: Thu Apr 05, 2012 6:41 pm

Re: Quads, sprites and coordinate systems

Post by target.san » Mon Feb 26, 2018 5:46 pm

Thanks for your time

Although samples you provided prove that quads were designed to work with pixel-based units. Meshes may be an option though, especially for static tile grids.

User avatar
pgimeno
Party member
Posts: 1500
Joined: Sun Oct 18, 2015 2:58 pm

Re: Quads, sprites and coordinate systems

Post by pgimeno » Mon Feb 26, 2018 8:38 pm

That's not really exclusive of quads, it's all about the transformation functions. When scaling, everything gets zoomed. Even lines get thicker.

Code: Select all

function love.draw()
  local lg = love.graphics
  lg.translate(400, 300)
  lg.scale(100,100)
  lg.line(-3,-2,3,2)
end
Attachments
thicker-line.png
thicker-line.png (6.62 KiB) Viewed 753 times
Thrust II Reloaded - GifLoad for Löve - GSpöt GUI - My NotABug.org repositories - portland (mobile orientation)
The MS-Github repositories I had have been closed after the acquisition announcement and will be removed in the near future.

target.san
Prole
Posts: 8
Joined: Thu Apr 05, 2012 6:41 pm

Re: Quads, sprites and coordinate systems

Post by target.san » Mon Feb 26, 2018 9:26 pm

Thanks, I know this.
Unfortunately, this still doesn't answer what's the "right" way in Love2D to work with non-pixel scene units.

User avatar
sefan
Prole
Posts: 22
Joined: Fri Jul 31, 2015 7:03 am
Contact:

Re: Quads, sprites and coordinate systems

Post by sefan » Wed Mar 07, 2018 3:54 pm

My way to handle units is like this. Using it in my current project.

Code: Select all

width, height = love.graphics.getDimensions( )
unit = 0
--To get the same number of units on any resolution
--1 unit is the smallest of width/24 or height/18
if width/24 < height/18 then
	unit = width/24
else
	unit = height/18
end
img = love.graphics.newImage('img.png')
quad = love.graphics.newQuad(  0,   0,   16, 16,   img:getHeight(), img:getWidth())
....
--Draw the quad at position x = 1*unit, y = 1*unit with the size 1*unit
love.graphics.draw(img, quad, unit, unit, 0,16/unit, 16/unit)

Post Reply

Who is online

Users browsing this forum: Exabot [Bot], Google [Bot], ivan, zorg and 5 guests