# Wrapping a texture onto a curve

Hey guys!

This project takes an image or texture and wraps it onto a curve. I used the function for a sine wave to draw the curve, and then used the derivative to find the slope and get the normals for the curve for more accurate mapping. I thought this might be useful if I ever decided to create a snowboarding game or something, like Alto’s Adventure.

If you want to make a new curve, you’ll have use some calculus wizardry and math out the derivative as well.

There is a way to find the length of the curve, using more calculus and integration. As far as I know, though, Codea doesn’t have an integration function, so I haven’t been able to figure it out yet. If anyone could help me figure it out, I would really appreciate it! Right now my code kind of stretches and squishes the texture because I’m only using the x-value to find the texture coordinates. Using the curve length instead would hopefully keep the texture more consistent.

Hope you enjoy! Try playing around with the texture a bit! And thanks for any help you guys can offer!

``````
--# Main
-- Curve Texture

displayMode(FULLSCREEN)
function setup()
f = function(x)
x = x + 0.000001
local y = math.sin(x/50)*50-x+700 -- Base function
local s = math.cos(x/50)-1 -- Derivative
-- local d = HOW DO YOU DO INTEGRALS???
s = -1/s
s = math.atan(s)
return y,s
end

parameter.watch("1/DeltaTime")
img = readImage("Cargo Bot:Crate Blue 1")
tex = image(100,50)
setContext(tex)
sprite(img,25,25,50)
sprite(img,75,25,50)

YouWantStripes = false -- CHANGE THIS TO TRUE/FALSE

if YouWantStripes then
noSmooth()
fill(255)
rect(0,0,100,50)
fill(200)
rect(0,10,100,50)
fill(150)
rect(0,20,100,50)
fill(100)
rect(0,30,100,50)
fill(50)
rect(0,40,100,50)
smooth()
end
setContext()

m = mesh()
m.texture = tex
end

function draw()
background(40,40,50)

res = 10

stroke(255)
strokeWidth(5)

local verts = {}
local texCoords = {}
local cols = {}
for x = 0,ElapsedTime*200,res do
local x1 = x
local y1,s1 = f(x1)
local x2 = x + res
local y2,s2 = f(x2)
local v1,v2 = vec2(x1,y1),vec2(x2,y2)
local v3 = vec2(x2,y2)-vec2(tex.height):rotate(s2)
local v4 = vec2(x1,y1)-vec2(tex.height):rotate(s1)
table.insert(verts,v1)
table.insert(verts,v2)
table.insert(verts,v3)
table.insert(verts,v3)
table.insert(verts,v4)
table.insert(verts,v1)
local c1 = x1%(tex.width/2)/tex.width
local c2 = c1 + (x2-x1)/tex.width
table.insert(texCoords,vec2(c1,1))
table.insert(texCoords,vec2(c2,1))
table.insert(texCoords,vec2(c2,0))
table.insert(texCoords,vec2(c2,0))
table.insert(texCoords,vec2(c1,0))
table.insert(texCoords,vec2(c1,1))
for i = 1,6 do table.insert(cols,color(255)) end
end
m.vertices = verts
m.texCoords = texCoords
m.colors = cols

m:draw()
end

``````

@Dwins Very interesting. I’m sure that will have a lot of uses.

@Dwins Here’s an example that calculates green parallel points on both sides of a red point trail. You don’t need calculus. Two pairs of green points could be used to create a rectangle that can be used for the mesh image. I didn’t bother to code the mesh portion. Drag your finger to draw a red trail. Lift your finger to display the green parallel points. Drag your finger again to draw another red trail.

``````displayMode(FULLSCREEN)

function setup()
tab={}
end

function calc(x1,y1,x2,y2)
mx=(x1+x2)/2
my=(y1+y2)/2
v=vec2(x2-x1,y2-y1)
v1=v1:normalize()*20
v2=v2:normalize()*20
end

function draw()
background(40, 40, 50)
fill(255)
text("Drag your finger to create a red trail",WIDTH/2,HEIGHT-50)
text("Lift your finger to see a green outline",WIDTH/2,HEIGHT-100)
for z=1,#tab do
fill(255,0,0)
ellipse(tab[z].x,tab[z].y,4)
if done then
if z>1 then
calc(tab[z-1].x,tab[z-1].y,tab[z].x,tab[z].y)
fill(0,255,0)
ellipse(v1.x+mx,v1.y+my,3)
ellipse(v2.x+mx,v2.y+my,3)
end
end
end
end

function touched(t)
if t.state==BEGAN then
tab={}
done=false
end
if t.state==MOVING then
table.insert(tab,vec2(t.x,t.y))
end
if t.state==ENDED then
done=true
end
end
``````

@dave1707 Oh, that is a bit easier than using calculus…although I think calculus is a bit more precise because it takes the slope at the point instead of the slope between two points. Thanks though, that’s a really cool example!

Any ideas on how to keep the texture from stretching?

I’m just starting my Senior year in High School, so I think my brain is still in use-calculus-for-everything mode

@Dwins I don’t think it matters that much which point is used. It don’t think it needs to be that accurate. I don’t think you can keep an image from stretching or squeezing if you take a rectangular image and put it on a curved surface. Anyways, I like the stretching and squeezing.

Got it.

``````
--# Main
-- Curve Texture

displayMode(FULLSCREEN)
function setup()
f = function(x)
x = x + 0.000001
local y = math.sin(x/50)*50-x+700 -- Base function
local s = math.cos(x/50)-1 -- Derivative
s = -1/s
s = math.atan(s)
return y,s
end

parameter.watch("1/DeltaTime")
img = readImage("Cargo Bot:Crate Blue 1")
tex = image(100,50)
setContext(tex)
sprite(img,25,25,50)
sprite(img,75,25,50)

YouWantStripes = false -- CHANGE THIS TO TRUE/FALSE

if YouWantStripes then
noSmooth()
fill(255)
rect(0,0,100,50)
fill(200)
rect(0,10,100,50)
fill(150)
rect(0,20,100,50)
fill(100)
rect(0,30,100,50)
fill(50)
rect(0,40,100,50)
smooth()
end
setContext()

m = mesh()
m.texture = tex

end

function draw()
background(40,40,50)

res = 16

stroke(255)
strokeWidth(5)

local verts = {}
local texCoords = {}
local cols = {}
d = 0
for x = 0,ElapsedTime*200,res do
local x1 = x
local y1,s1 = f(x1)
local x2 = x + res
local y2,s2 = f(x2)
local v1,v2 = vec2(x1,y1),vec2(x2,y2)
local v3 = vec2(x2,y2)-vec2(tex.height):rotate(s2)
local v4 = vec2(x1,y1)-vec2(tex.height):rotate(s1)
table.insert(verts,v1)
table.insert(verts,v2)
table.insert(verts,v3)
table.insert(verts,v3)
table.insert(verts,v4)
table.insert(verts,v1)
local d1 = d
d = d + math.sqrt((x2-x1)^2+(y2-y1)^2)
local d2 = d
local c1 = d1%(tex.width/2)/tex.width
local c2 = c1 + (d2-d1)/tex.width
table.insert(texCoords,vec2(c1,1))
table.insert(texCoords,vec2(c2,1))
table.insert(texCoords,vec2(c2,0))
table.insert(texCoords,vec2(c2,0))
table.insert(texCoords,vec2(c1,0))
table.insert(texCoords,vec2(c1,1))
for i = 1,6 do table.insert(cols,color(255)) end
end
m.vertices = verts
m.texCoords = texCoords
m.colors = cols

m:draw()

end

``````