Hi.
Well, I played around with some stuff, and here’s what I’ve got so far:
display.setDefault("textureWrapX", "repeat") display.setDefault("textureWrapY", "repeat") local fileName = "Texture.png" local imageSheetOptions = { frames = { { x = 0, y = 0, width = 64, height = 64 }, { x = 0, y = 64, width = 64, height = 64 }, } } local imageSheet = graphics.newImageSheet(fileName, imageSheetOptions) local rect = display.newImageRect("Texture.png", 64, 128) rect.x = 200 rect.y = 200 rect.width = 64 rect.height = 128 rect.fill = { type = "image", sheet = imageSheet, frame = 1 } --rect.fill.scaleY = 0.5 local W, H = 64, 128 local frames = {} local nframes = #imageSheetOptions.frames for i, frame in ipairs(imageSheetOptions.frames) do local x, y, w, h = frame.x / W, frame.y / H, frame.width / W, frame.height / H frames[#frames + 1] = ("\n\t\t\tFrames[%i] = vec4(%f, %f, %f, %f);"):format(i - 1, x, y, w, h) end do local kernel = { category = "filter", name = "copy" } kernel.vertexData = { { name = "frame", default = 1, min = 1, max = nframes, index = 0 } } kernel.vertex = [[varying P\_UV vec2 uv\_rel; P\_POSITION vec2 VertexKernel (P\_UV vec2 pos) { P\_UV vec4 Frames]] .. ("[%i];"):format(nframes) .. [[]] .. table.concat(frames, "") .. [[P\_UV vec4 frame = Frames[int(CoronaVertexUserData.x) - 1]; uv\_rel = frame.xy + frame.zw \* CoronaTexCoord; return pos; } ]] kernel.fragment = [[varying P\_UV vec2 uv\_rel; P\_COLOR vec4 FragmentKernel (P\_UV vec2 uv) { return CoronaColorScale(texture2D(CoronaSampler0, uv\_rel)); }]] graphics.defineEffect(kernel) end do local kernel = { category = "filter", name = "scale" } kernel.vertexData = { { name = "x", default = 0, min = -65535, max = 65535, index = 0 }, { name = "y", default = 0, min = -65535, max = 65535, index = 1 }, { name = "scaleX", default = 1, min = 0, max = 10, index = 2 }, { name = "scaleY", default = 1, min = 0, max = 10, index = 3 } } kernel.vertex = [[varying P\_UV vec2 uv\_rel; P\_POSITION vec2 VertexKernel (P\_POSITION vec2 pos) { uv\_rel = step(CoronaVertexUserData.xy, pos) / CoronaVertexUserData.zw; return pos; }]] kernel.fragment = [[varying P\_UV vec2 uv\_rel; P\_COLOR vec4 FragmentKernel (P\_UV vec2 uv) { return CoronaColorScale(texture2D(CoronaSampler0, fract(uv\_rel))); }]] graphics.defineEffect(kernel) end do -- Kernel -- local kernel = { category = "filter", name = "copy\_scale" } kernel.graph = { nodes = { copy = { effect = "filter.custom.copy", input1 = "paint1" }, scale = { effect = "filter.custom.scale", input1 = "copy" }, }, output = "scale" } graphics.defineEffect(kernel) end rect.fill.effect = "filter.custom.copy\_scale" rect.fill.effect.scale.x = rect.x rect.fill.effect.scale.y = rect.y rect.fill.effect.scale.scaleY = .5 timer.performWithDelay(1500, function(event) rect.fill.effect.copy.frame = (event.count - 1) % 2 + 1 end, 0)
There are some filtering issues going on, but that’s standard image sheet stuff.
You can print out the kernel.vertex (and others, of course) if you want to see what the final code looks like.
The multi-pass behavior is strange… the first effect seems to get full-image texture coordinates, while the second uses image sheet-style ones. If not for this, hard-coding the texture coordinates wouldn’t have been necessary. It seems like a Corona bug, but maybe I’m overlooking something.
The two passes were only really to avoid that hard-coding, so they don’t really serve much purpose. I’ll see about tightening this up into one go.
Unfortunately, without some nicer way to grab the uv-rects (my intuition is leaning toward some API like graphics.getFrameRect(image_sheet, frame), that returns the raw [0-1] values in some form, as a table or four values, for instance), some of those calculations done early on seem to be necessary. Strictly speaking you don’t need to bake them into the shader like I did: just get them on the Lua side and then pass them in as four inputs, instead of the frame, and then the shader would even be reusable. (Harder to do that in one pass, though.)
Also, there might be a way to effect this more cleanly with snapshots, say with a shader like the scale one above, sans the need for relative texture coordinates. I gave that a try last night without any luck, but then it was already 2 AM and I probably wasn’t at my best. 