Page 1 of 2

Rotate image on a quad

Posted: Sun Jan 29, 2023 7:26 pm
by Bobble68
Hello there LÖVE forums, I am once again asking for your knowledge and assistance.

I've been working on a game with a level editor where you can draw out polygons for the level platforms, and now I have made it so you can convert them into physics objects.

Each platform has a repeating texture, which I have managed using setWrap(), then drawing it on a quad the size of the screen, and then finally stenciling it - however my issue is that now they are physics objects, they can also rotate. Just setting r on the draw function rotates the whole quad and not just the texture, which means it no longer covers the whole screen.

Is there a good way to achieve what I want?

Re: Rotate image on a quad

Posted: Sun Jan 29, 2023 7:59 pm
by Bigfoot71
If I understood correctly what you are describing why not just use `love.graphics.rotate` inside `love.graphics.push` ?

Here is what I mean:

Code: Select all

love.graphics.push()
love.graphics.translate(cx, cy)
love.graphics.rotate(polygon:getRotation())
love.graphics.translate(-cx, -cy)
  
love.graphics.stencil(function()
    love.graphics.polygon("fill", polygon)
end, "replace", 1)
love.graphics.setStencilTest("greater", 0)

love.graphics.draw(
    sprite, cx, cy, sprite_angle, 1, 1,
    sprite:getWidth()/2,
    sprite:getHeight()/2
)

love.graphics.setStencilTest()
love.graphics.pop()
Is that what you were describing?

Image

Here you can manage the rotation of the polygon and the texture separately.

Re: Rotate image on a quad

Posted: Sun Jan 29, 2023 8:40 pm
by Bobble68
Bigfoot71 wrote: Sun Jan 29, 2023 7:59 pm Is that what you were describing?
Not quite - the main issue is that it needs to be a repeating texture, like so:
Untitled.png
Untitled.png (111.79 KiB) Viewed 3591 times
Here is what I'm currently working with, which works untill you need to rotate the texture around a point

Code: Select all

image = love.graphics.newImage("anImage.png")

function love.draw()
  wrappedDraw(image, love.graphics.getWidth()/2, love.graphics.getHeight()/2, 0)
end



function wrappedDraw(drawable, x, y, r, scale)
  if not scale then
    scale = 1
  end
  if not r then
    r = 1
  end
  drawable:setWrap( "repeat", "repeat" )
  local quad = love.graphics.newQuad( -x, -y, love.graphics.getWidth(), love.graphics.getHeight(), drawable:getWidth()*scale, drawable:getHeight()*scale )
  love.graphics.draw( drawable, quad, 0+love.graphics.getWidth()/2, 0+love.graphics.getHeight()/2, 0, 1, 1, love.graphics.getWidth()/2, love.graphics.getHeight()/2)
end
Appologies for my code, I'm aware I probably do things inefficiently.

Re: Rotate image on a quad

Posted: Sun Jan 29, 2023 10:15 pm
by darkfrei
See also: viewtopic.php?f=4&t=93939

You can use meshes for it:

Code: Select all

love.window.setMode(800, 800)
W, H = love.graphics.getDimensions( )

function love.load()
	local image = love.graphics.newImage('img-16.png')
	image:setWrap( "repeat" )
	image:setFilter("linear", "nearest")

	local n = 6 -- amount of tiles
	local k = 128 -- size of tile
	local s = n*k -- size of screen
	
	local vertices = {
		{0, 0, 0, 0, 1,1,1},
		{0, s, 0, n, 1,1,1},
		{s, s, n, n, 1,1,1},
		{s, 0, n, 0, 1,1,1},
	}
	mesh = love.graphics.newMesh( vertices, "fan")
	mesh:setTexture(image)
end

Code: Select all

function love.draw()
	love.graphics.draw(mesh)
end
2023-01-29T23_15_19-Untitled.png
2023-01-29T23_15_19-Untitled.png (108.96 KiB) Viewed 3543 times
So, make the round mesh and rotate it around the middle of it.

Re: Rotate image on a quad

Posted: Mon Jan 30, 2023 10:57 am
by Bigfoot71
I'm still not sure I understand the problem, is it the `r` variable you forgot to `draw`?

It doesn't matter, if you can't follow darkfrei's instructions, otherwise here's what I wrote to rotate the texture:

Code: Select all

function wrappedDraw(drawable, x, y, r, scale)

    r = r or 0
    scale = scale or 1

    drawable:setWrap( "repeat", "repeat" )
    local quad = love.graphics.newQuad( -x, -y, love.graphics.getWidth(), love.graphics.getHeight(), drawable:getWidth()*scale, drawable:getHeight()*scale )
    love.graphics.draw( drawable, quad, 0+love.graphics.getWidth()/2, 0+love.graphics.getHeight()/2, r, 1, 1, love.graphics.getWidth()/2, love.graphics.getHeight()/2)

end
You will notice that instead of writing:

Code: Select all

if not value then
  value = 1
end
You can simply write:

Code: Select all

value = value or 1

Re: Rotate image on a quad

Posted: Mon Jan 30, 2023 11:02 am
by Bobble68
darkfrei wrote: Sun Jan 29, 2023 10:15 pm You can use meshes for it:
Ah I see! I'm unfamilar with meshes (this is the first I knew love could handle them), so I'll look into them. Is this any better than just drawing a quad big enough to fill the entire screen?

Re: Rotate image on a quad

Posted: Mon Jan 30, 2023 11:13 am
by Bobble68
Bigfoot71 wrote: Mon Jan 30, 2023 10:57 am You will notice that instead of writing:

Code: Select all

if not value then
  value = 1
end
You can simply write:

Code: Select all

value = value or 1
Oh that's very neat! Time to update all my functions...

What I was looking for before was to just fill the whole screen, what I'm trying to avoid is drawing outside the screen area, and not leaving any undrawn area, otherwise you get these corners.
Untitled.png
Untitled.png (716.25 KiB) Viewed 3494 times
Appologies if I'm not being clear, hopefully looking more into meshes will give a solution.


Edit: Upon looking more into meshes, I'm less certain how I can use this to fix my issue if I make a mesh that matches the level polygon, wouldn't that make it difficult to set the UVs correctly?

Re: Rotate image on a quad

Posted: Mon Jan 30, 2023 12:25 pm
by Bigfoot71
Bobble68 wrote: Mon Jan 30, 2023 11:13 am
Bigfoot71 wrote: Mon Jan 30, 2023 10:57 am You will notice that instead of writing:

Code: Select all

if not value then
  value = 1
end
You can simply write:

Code: Select all

value = value or 1
Oh that's very neat! Time to update all my functions...

What I was looking for before was to just fill the whole screen, what I'm trying to avoid is drawing outside the screen area, and not leaving any undrawn area, otherwise you get these corners.

Untitled.png

Appologies if I'm not being clear, hopefully looking more into meshes will give a solution.


Edit: Upon looking more into meshes, I'm less certain how I can use this to fix my issue if I make a mesh that matches the level polygon, wouldn't that make it difficult to set the UVs correctly?
Ah okay, unfortunately, mesh or not apart from extending the edges beyond the screen, I don't really see how you could do it to be honest (unless a solution escapes me at this moment)...

Otherwise for the UVs it's very simple when you understand, they go from 0 to 1, where 0.0 is the origin of the image (top left for Löve or bottom left for other engines) and 1.1 is bottom right (or top right...).

Here is an example I made using a mesh:

Code: Select all

local GW, GH = love.graphics.getDimensions()
local GOX, GOY = GW/2, GH/2

local backgroundImage = love.graphics.newImage("background.jpg")
backgroundImage:setWrap("repeat", "repeat") -- Always important to call this method

local backgroundAngle = 0

-- Set a distance larger than the screen size for the vertices of the mesh
local distance = 2 * math.max(GW, GH)

-- Create an array for the texture coordinates of the mesh
-- To repeat the texture it is necessary to normalize from 0 to 1 by dividing the size of the mesh by the size of the texture
-- If we defined the corners only with 0 and 1 the texture would simply be stretched.
local meshVertices = {
    {-distance, -distance, 0, 0},
    {distance, -distance, GW / backgroundImage:getWidth(), 0},
    {distance, distance, GW / backgroundImage:getWidth(), GH / backgroundImage:getHeight()},
    {-distance, distance, 0, GH / backgroundImage:getHeight()}
}

-- Create a mesh from the array
local mesh = love.graphics.newMesh(meshVertices, "fan")
mesh:setTexture(backgroundImage)


-- We do it all --

function love.update(dt)
    backgroundAngle = backgroundAngle + dt
end

function love.draw()
  love.graphics.setColor(1, 1, 1)
  love.graphics.draw(mesh, GOX, GOY, backgroundAngle, 1, 1, GOX, GOY)
end
Image

Re: Rotate image on a quad

Posted: Mon Jan 30, 2023 1:23 pm
by darkfrei
Bobble68 wrote: Mon Jan 30, 2023 11:13 am Edit: Upon looking more into meshes, I'm less certain how I can use this to fix my issue if I make a mesh that matches the level polygon, wouldn't that make it difficult to set the UVs correctly?
So,

Code: Select all

function love.load()
	local image = love.graphics.newImage('img-16.png')
	image:setWrap( "repeat" )
	image:setFilter("linear", "nearest")

	local n = 6 -- amount of tiles
	local k = 128 -- size of tile
	local s = n*k -- size of screen
	
	local vertices = {
		{0, 0, 0, 0, 1,1,1},
		{s, 0, n, 0, 1,1,1},
		{0, s, 0, n, 1,1,1},
		{s, s, n, n, 1,1,1},
	}
	mesh = love.graphics.newMesh( vertices, "strip") -- strip, not fan!
	mesh:setTexture(image)
	Angle = 0
end

Code: Select all

local function rotateMesh (mesh, s, n, angle)
	local u1 =  n*math.cos(angle)
	local u2 =  n*math.sin(angle)
	local v1 =  n*math.sin(angle)
	local v2 = -n*math.cos(angle)
	mesh:setVertex(2, s, 0, u1, v1)
	mesh:setVertex(3, 0, s, u2, v2)
	mesh:setVertex(4, s, s, u1+u2, v1+v2)
end
 
function love.update(dt)
	local n, s = 6, 128*6
	Angle = Angle + 0.1*dt
	rotateMesh (mesh, s, n, Angle)
end

Code: Select all

function love.draw()
	love.graphics.draw(mesh)
end
2023-01-30T14_22_35-Untitled.png
2023-01-30T14_22_35-Untitled.png (170.15 KiB) Viewed 3442 times

Re: Rotate image on a quad

Posted: Mon Jan 30, 2023 2:35 pm
by Bobble68
darkfrei wrote: Mon Jan 30, 2023 1:23 pm
Bobble68 wrote: Mon Jan 30, 2023 11:13 am Edit: Upon looking more into meshes, I'm less certain how I can use this to fix my issue if I make a mesh that matches the level polygon, wouldn't that make it difficult to set the UVs correctly?
So,

Code: Select all

function love.load()
	local image = love.graphics.newImage('img-16.png')
	image:setWrap( "repeat" )
	image:setFilter("linear", "nearest")

	local n = 6 -- amount of tiles
	local k = 128 -- size of tile
	local s = n*k -- size of screen
	
	local vertices = {
		{0, 0, 0, 0, 1,1,1},
		{s, 0, n, 0, 1,1,1},
		{0, s, 0, n, 1,1,1},
		{s, s, n, n, 1,1,1},
	}
	mesh = love.graphics.newMesh( vertices, "strip") -- strip, not fan!
	mesh:setTexture(image)
	Angle = 0
end

Code: Select all

local function rotateMesh (mesh, s, n, angle)
	local u1 =  n*math.cos(angle)
	local u2 =  n*math.sin(angle)
	local v1 =  n*math.sin(angle)
	local v2 = -n*math.cos(angle)
	mesh:setVertex(2, s, 0, u1, v1)
	mesh:setVertex(3, 0, s, u2, v2)
	mesh:setVertex(4, s, s, u1+u2, v1+v2)
end
 
function love.update(dt)
	local n, s = 6, 128*6
	Angle = Angle + 0.1*dt
	rotateMesh (mesh, s, n, Angle)
end

Code: Select all

function love.draw()
	love.graphics.draw(mesh)
end
2023-01-30T14_22_35-Untitled.png
Thats nearly perfect! Only issue is it needs to be able to be rotated around a specific point, rather than just 0,0 so it doesn't shift when a physics object rotate. I tried to figure out how to do it, though I got wrong (though interesting to look at) results.
Untitled.png
Untitled.png (1.08 MiB) Viewed 3427 times