Newb mesh question

Could someone please give me a small example of how to stretch a large texture over a mesh divided into many polygons? For instance, putting a flag image over the cloth mesh in the cloth example. Or just an image stretched over a flat 2d mesh. Thanks.

If I understand correctly what you want, you might like to take a look at my “flexible words” example in http://www.twolivesleft.com/Codea/Talk/discussion/639/flexible-words/p1

(I can never remember how to embed youtube videos in this forum, the link is http://youtu.be/NDcBdeVnweY)

Thanks, @Andrew_Stacey. The only thing I care about is the UV mapping, and I think the answer is somewhere in the following code I ripped from your example:

    method = REPELL
    ode = TENSION
    --showpoints = true
    screen = mesh()
    side = 50
    spr = 1
    fr = .1
    ht = side*math.sqrt(3)/2
    local n = math.floor(WIDTH/side)+1
    local m = math.floor(HEIGHT/ht)+1
    local ad,v,rpts,pt
    local pts = {}
    tri = {}
    for i=1,m do
        rpts = {}
        ad = (1-i%2)*side/2
        for j = 1,n do
            v = vec2(ad + (j-1)*side,(i-1)*ht)
            pt = {point = v, velocity = vec2(0,0), neighbours = {}}
            
            if j ~= 1 then
                table.insert(pt.neighbours,rpts[j-1])
                table.insert(rpts[j-1].neighbours,pt)
            end
            if i ~= 1 then
                table.insert(pt.neighbours,pts[i-1][j])
                table.insert(pts[i-1][j].neighbours,pt)
                if i%2 == 1 then
                    if j ~= 1 then
                        table.insert(pt.neighbours,pts[i-1][j-1])
                        table.insert(pts[i-1][j-1].neighbours,pt)
                        table.insert(tri,{pt,rpts[j-1],pts[i-1][j-1]})
                        table.insert(tri,{pt,pts[i-1][j-1],pts[i-1][j]})
                    end
                else
                    if j ~= n then
                        table.insert(pt.neighbours,pts[i-1][j+1])
                        table.insert(pts[i-1][j+1].neighbours,pt)
                        table.insert(tri,{pt,pts[i-1][j],pts[i-1][j+1]})
                    end
                    if j ~= 1 then
                        table.insert(tri,{pt,rpts[j-1],pts[i-1][j]})
                    end
                end
            end
            table.insert(rpts,pt)
        end
        table.insert(pts,rpts)
    end
    points = {}
    for k,v in ipairs(pts) do
        for l,u in ipairs(v) do
            table.insert(points,u)
        end
    end
    local n
    for k,v in ipairs(points) do
        n = 0
        for l,u in ipairs(v.neighbours) do
            n = n + 1
        end
        if n == 6 then
            v.fixed = false
        else
            v.fixed = true
        end
    end
    img = image(WIDTH,HEIGHT)
    pushStyle()
    setContext(img)
    fill(0, 107, 255, 255)
    noSmooth()
    rect(0,0,WIDTH,HEIGHT)
    font("Noteworthy-Bold")
    fontSize(160)
    fill(255, 255, 255, 255)
    local fm = fontMetrics()
    local h = 1.8*fm.xHeight
    fill(0, 255, 21, 255)
    text("Words",WIDTH/2,HEIGHT/2 + h)
    text("are",WIDTH/2,HEIGHT/2)
    text("flexible",WIDTH/2,HEIGHT/2 - h)
    setContext()
    popStyle()
    screen.texture = img
    texc = {}
    for k,v in ipairs(tri) do
        for l,u in ipairs(v) do
            table.insert(texc,vec2(u.point.x/WIDTH,u.point.y/HEIGHT))
        end
    end
    screen.texCoords = texc

Now I just have to spend a little time deciphering. Thanks for pointing me in the right direction.

I am having a little trouble getting this figured out, the code is a little complex. What I want to do is put a texture on a mesh like it is pictured left, NOT how it is pictured right. :
Photobucket

I think I need to create a list of texture coordinates and somehow tie those to vertices in my mesh, just having a hard time getting that done. If there is a simpler example I would love to see it, otherwise I will keep trying to figure it out.

Here’s another one which also renders a picture to a mesh. You’ll need to change the picture.




-- Use this function to perform your initial setup
--supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)
ALLOW_ODD = false
SHOW_PICTURE = true
GAME = 1
GRID = 2
OPACITY = 3
SUCCESS = 4
drawfn = {}
touchedfn = {}
function setup()
    bgcolour = color(40, 40, 50)
    state = GRID
    mrows = 6
    mcolumns = 5
    mwidth = WIDTH/mrows
    mheight = HEIGHT/mcolumns
    aduration = .8
    rows = 4
    columns = 4
    opacity = 127
    picture = "Documents:Snowman"
    smash = mesh()
    smash:addRect(0,0,WIDTH,HEIGHT)
    smash.texture = picture
    smash.texCoords = {
        vec2(0,0),
        vec2(0,1),
        vec2(1,1),
        vec2(0,0),
        vec2(1,1),
        vec2(1,0)
    }
    
end

function initialise()
    mash = mesh()
    fold, unfold = foldem(rows,columns)
    rwidth = WIDTH/rows
    rheight = HEIGHT/columns
    mash.texture = picture
    local x,y
    places = {}
    for i = 1,rows do
        x = (i-.5)*rwidth
        for j = 1,columns do
            y = (j-.5)*rheight
            table.insert(places,{x,y})
        end
    end
    -- kth piece is in p[k]th place, start with blank at top left
    local pp = KnuthShuffle(rows*columns-1,ALLOW_ODD)
    while is_identity(pp) do
        pp = KnuthShuffle(rows*columns-1,ALLOW_ODD)
    end
    p = {1}
    for k,v in ipairs(pp) do
        p[k+1] = v+1
    end
    -- kth place contains pi[k]th piece
    pi = {}
    for k = 1,rows*columns do
        pi[p[k]] = k -- inverse of p
        mash:addRect(places[p[k]][1],places[p[k]][2],rwidth,rheight)
    end
    if SHOW_PICTURE then
        mash:setRectColor(1,255,255,255,opacity)
    else
        mash:setRectColor(1,0,0,0,0)
    end
    local ij
    for k = 2,rows*columns do
        ij = unfold(k)
        mash:setRectTex(k,
                (ij[1]-1)/rows,
                (ij[2]-1)/columns,
                1/rows,
                1/columns
                )
    end
end

function draw()
    drawfn[state]()
end

drawfn[GAME] = function ()
    background(bgcolour)
    if animate then
        local t = (ElapsedTime - atime)/aduration
        local last
        if t > 1 then
            last = true
            t = 1
        end
        -- smooth out the motion
        t = (3 - 2*t)*t*t
        for k,v in ipairs(animate) do
            
            mash:setRect(v[1],
                t*v[3][1] + (1-t)*v[2][1],
                t*v[3][2] + (1-t)*v[2][2],
                rwidth,
                rheight)
        end
        if last then
            animate = nil
        end
    else
        if is_identity(p) then
            state = SUCCESS
        end
    end
    mash:draw()
end

drawfn[SUCCESS] = function ()
    if not set then
        backingMode(RETAINED)
    mash:draw()
    font("AcademyEngravedLetPlain")
    fill(201, 180, 29, 255)
    fontSize(100)
    textWrapWidth(0)
    text("Congratulations!",WIDTH/2,HEIGHT/2)
    
        stime = ElapsedTime
        set = true
    end
    local x,y,s,r,g,b
    x = math.random(1,WIDTH)
    y = math.random(1,HEIGHT)
    s = math.random(25,75)
    r = math.random(0,255)
    g = math.random(0,255)
    b = math.random(0,255)
    fill(r,g,b,127)
    ellipse(x,y,s)
    if ElapsedTime - stime > 5 then
        set = false
        backingMode(STANDARD)
        state = GRID
    end
end

drawfn[GRID] = function ()
    background(bgcolour)
    local sw,sh = rows*mwidth,columns*mheight
    smash:setRect(1,sw/2,sh/2,sw,sh)
    smash:draw()
    noFill()
    strokeWidth(2)
    stroke(166, 170, 23, 255)
    noSmooth()
    rectMode(CENTER)
    for i = 1,mrows do
        for j = 1,mcolumns do
            rect((i - .5)*mwidth,(j - .5)*mheight,mwidth,mheight)
        end
    end
    fontSize(50)
    textWrapWidth(3*WIDTH/4)
    textAlign(CENTER)
    local msg = "Choose a grid size by dragging the corner of the picture.  Double-tap to select."
    local w,h = textSize(msg)
    local x,y = WIDTH/2,HEIGHT-h/2
    fill(0,0,0,127)
    noStroke()
    rect(x,y,w,h)
    fill(25, 54, 156, 255)
    text(msg,x,y)
end

drawfn[OPACITY] = function ()
    background(bgcolour)
    tint(255,255,255,opacity)
    spriteMode(CORNER)
    sprite(picture,0,0,WIDTH,HEIGHT)
    fontSize(50)
    textWrapWidth(3*WIDTH/4)
    textAlign(CENTER)
    local msg = "The picture is shown in the blank square.  Drag a finger to choose how visible it is.  Double-tap to select."
    local w,h = textSize(msg)
    local x,y = WIDTH/2,HEIGHT-h/2
    fill(0,0,0,127)
    noStroke()
    rect(x,y,w,h)
    fill(25, 54, 156, 255)
    text(msg,x,y)
end

function touched(touch)
    touchedfn[state](touch)
end

touchedfn[GRID] = function (touch)
    if touch.state == MOVING then
        rows = math.max(2,math.floor(touch.x/mwidth) + 1)
        columns = math.max(2,math.floor(touch.y/mheight) + 1)
    end
    if touch.state == ENDED and touch.tapCount == 2 then
        state = OPACITY
    end
end

touchedfn[GAME] = function (touch)
    if animate then
        return
    end
    if touch.state == ENDED then
        local tpiece = {
            math.floor(touch.x/rwidth) + 1,
            math.floor(touch.y/rheight) + 1
        }
        if lonedist(unfold(p[1]),tpiece) == 1 then
            local l = fold(unpack(tpiece))
            animate = {
                {1,places[p[1]],places[l]},
                {pi[l],places[l],places[p[1]]}
            }
            atime = ElapsedTime
            -- piece 1 (blank) is now at place l,
            -- what is now at l is the blank (piece 1),
            -- what was in place l (pi[l]) is now 
            -- where the blank was (p[1]),
            -- what is where the blank was (p[1]) is
            -- what was in place l (pi[l])
            p[1],pi[l],p[pi[l]],pi[p[1]] = l,1,p[1],pi[l]
        end
    end
end

touchedfn[OPACITY] = function (touch)
    if touch.state == MOVING then
        opacity = 255*math.min(1,math.max(0,(1.2*touch.x/WIDTH - .1)))
    end
    if touch.state == ENDED and touch.tapCount == 2 then
        initialise()
        state = GAME
    end
end

function KnuthShuffle(n,odd)
    local l
    local o = 0
    local p = {}
    for k = 1,n do
        p[k] = k
    end
    for k = 1,n-1 do
        l = math.random(k,n)
        if l ~= k then
            p[k],p[l] = p[l],p[k]
            o = 1 - o
        end
    end
    if not odd and o == 1 then
        p[1],p[2] = p[2],p[1]
    end
    return p
end

function lonedist(a,b)
    return math.abs(a[1] - b[1]) + math.abs(a[2] - b[2])
end

function foldem(r,c)
    return function (i,j)
            return (i-1)*c + j
        end,
        function (k)
            return {math.floor((k-1)/c)%r + 1,(k-1)%c + 1}
        end
end

function is_identity(p)
    for k,v in ipairs(p) do
        if v ~= k then
            return false
        end
    end
    return true
end

The key, for me, is to remember that the picture covers the unit square [0,1] x [0,1]. So I imagine laying out my mesh on that square and then reading off the coordinates of each vertex. Those are the texture coordinates.

That is very informative, @Andrew_Stacey, thanks for this example. It seems like there is not enough documentation about how to do the texturing. After I fully grok it, I will add some info on this to the wiki.

that should do what you need, assuming all the quads with the same size:


function setup()
    img = readImage("SpaceCute:Health Heart")
    imgWidth = img.width
    imgHeight = img.height
    
    local numTileX = 4
    local numTileY = 4
    
    local tileWidth = imgWidth / numTileX
    local tileHeight = imgHeight / numTileY
    
    local tileU = 1 / numTileX
    local tileV = 1 / numTileY
    
    mesh = mesh()
    mesh.texture = img
    
    for i = 0, numTileX - 1 do
        for j = 0, numTileY - 1 do
            --mesh quads are centered on x,y, so a displace of 1/2 width, 1/2 height 
            --is required to set the image position in (0,0)
            local r = mesh:addRect((i+.5)*tileWidth,(j+.5)*tileHeight,
                tileWidth,tileHeight)
            mesh:setRectTex(r,i*tileU,j*tileV,tileU,tileV)
        end
    end
end


function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    pushMatrix()
    -- draw in the middle of the screen
    translate((WIDTH - imgWidth)/2,(HEIGHT - imgHeight)/2)
    mesh:draw()

    popMatrix()
    
end

I was a little slow, but finally I grasp how to texturemap using either texCoords OR setTextRec. I think I will write a tutorial to try and help other newbs get it. Thanks for all the help, @shrike and @Andrew_Stacey.

Yes, please do Vega. I need to switch my app over to Meshes some time and I know for a fact another idea I have will need them.

Now my question is… is it possible to apply a mesh to a drawn line?