Texture seams appearing at different aspect ratios

I’m having issues with texture seams appearing between objects I draw. Here’s a quick screenshot in the simulator in iPhone 4 mode:

Those floors and walls are composed of 32x32 pixel blocks placed next to each other. As long as I make sure to always place the images at integer values, there’s no problem. However, when I switch to iPad view, I get this: (Red boxes added to show problems.)

I’m using “letterbox” scaling mode. Here’s my config.lua:

[code]application =
{
content =
{
width = 320,
height = 480,
scale = “letterbox”,
xAlign = “center”,
yAlign = “center”,

imageSuffix =
{
["@2"] = 2,
},
},
}[/code]
My understanding of letterbox on larger devices is that it simply re-centers the content and ends up showing more without cropping or distorting the aspect ratio. Yet I’m getting behavior resembling what happens if I attempt to draw images on non-integer positions in iPhone 4 mode. I don’t actually have an iPad to test it on, but I do have an HTC Evo 4G which a 480×800 display and has similar issues on-phone.

What am I doing wrong here? Thanks for any help. [import]uid: 145887 topic_id: 26167 reply_id: 326167[/import]

Hey!

Can you post up some code to show how you are drawing the textures to the screen?

[import]uid: 84637 topic_id: 26167 reply_id: 106093[/import]

Sure!

Here is where the actual sprite creation is being done. (I was also getting some seam weirdness using the mask to shorten the last block, but the problem in the screenshot seems to exist outside of that and I suspect is the same problem, since the masking works perfectly in iPhone4 mode.)

Any texture passed to this function will be 32x32 (with a 64x64 @2 version). The mask is (as the filename says) a 40x40 image that’s all white except for a 4-pixel-wide block border with an @2 version.
[lua]–Constructor helper function that creates the sprites with the passed texture name.
– Can be called by derived classes with different textures after passing false for bInitSprites to the constructor
function Floor:_InitRectSprites(dLength, sTextureName)
–Make the RectSprite for each section
self._m_vRectSprites = {}
local nNumSections = math.ceil(dLength / Floor._v2dSectionSize.x)
for i = 1, nNumSections do
self._m_vRectSprites[i] = RectSprite.New(sTextureName, Vec2D.New(self._m_v2dPos.x + ((i - 1) * Floor._v2dSectionSize.x), self._m_v2dPos.y))
SpriteManager.Instance:AddRectSpriteToLayer(self._m_vRectSprites[i], SpriteManager.LEVEL_OBJECTS)
end

–We must mask the last section to exactly get the length
local nLastSectionLength = Floor._v2dSectionSize.x - ((nNumSections * Floor._v2dSectionSize.x) - dLength)
self._m_vRectSprites[nNumSections]:SetMask(graphics.newMask(“Masks/WhiteWith4BlackBorder_40x40.png”))
self._m_vRectSprites[nNumSections]:SetMaskOffset(Vec2D.New(-(Floor._v2dSectionSize.x - nLastSectionLength), 0))
end[/lua]
Here is the RectSprite constructor called in that function:

[lua]–Constructor
–sImageFileName is the image filename to load and v2dPos is the initial upper-left position
function RectSprite.New(sImageFileName, v2dPos)
–Make new object
local newRectSprite = {}
setmetatable(newRectSprite, RectSprite)

–Get and save the image’s unscaled size, if it hasn’t already been loaded
if RectSprite._ImageFileSizes[sImageFileName] == nil then
local image = display.newImage(sImageFileName)
if image == nil then
DebugFunctions.Traceback()
end
RectSprite._ImageFileSizes[sImageFileName] = Vec2D.New(image.width, image.height);
display.remove(image)
end
newRectSprite._m_v2dSize = RectSprite._ImageFileSizes[sImageFileName];

–Make the dynamically-scaled image
newRectSprite._m_ImageRect = display.newImageRect(sImageFileName, newRectSprite._m_v2dSize.x, newRectSprite._m_v2dSize.y)

–Init _m_v2dPosition and then set it to the passed position
newRectSprite._m_v2dPosition = Vec2D.New()
newRectSprite:SetPos(v2dPos)

return newRectSprite
end[/lua]
And, finally, here’s the SpriteManager function also called in the original function that actually inserts the image into a display group:
[lua]–Adds the passed RectSprite to the passed layer. Automatically removes it from it’s previous layer, if it already existed.
function SpriteManager:AddRectSpriteToLayer(pRectSprite, nLayer)
–Validate layer value
if DEBUG then
assert(nLayer >= 1 and nLayer <= SpriteManager.NUM_LAYERS)
end

–Remove from previous layer, if necessary
if self._m_mSpritesToDisplayGroups[pRectSprite] ~= nil then
self:RemoveSprite(pRectSprite)
end

–Insert into layer and save where it was put
self._m_vDisplayGroups[nLayer]:insert(pRectSprite._m_ImageRect)
self._m_mSpritesToDisplayGroups[pRectSprite] = nLayer
end[/lua]
Thanks for the help and let me know if you need anymore info! [import]uid: 145887 topic_id: 26167 reply_id: 106114[/import]

Bumping this in hope of a reply… [import]uid: 145887 topic_id: 26167 reply_id: 106566[/import]

I’d like to at least be told if this normal behavior. If it’s not, I can mess around and try and find the problem. But if Corona always has texture seam issues with content scaling, it would be good to know that now.

Thanks! [import]uid: 145887 topic_id: 26167 reply_id: 106656[/import]

I think I found what’s causing it:

self.\_m\_ImageRect.x = GeneralMath.RoundToNearest(self.\_m\_v2dPosition.x + (self.\_m\_v2dSize.x / 2), display.contentScaleX) self.\_m\_ImageRect.y = GeneralMath.RoundToNearest(self.\_m\_v2dPosition.y + (self.\_m\_v2dSize.y / 2), display.contentScaleY)

Basically, I was trying to prevent texture swimming here while scrolling by always trying to exactly position objects exactly on a physical pixel by rounding to the nearest contentScale. When I remove that, the problem goes away. (Well, the masks still cause problems, but apparently from what I’ve read, they really don’t scale well at all, so I should probably give up on that.)

Is this just not going to work or am I misunderstanding what contentScale means? [import]uid: 145887 topic_id: 26167 reply_id: 106678[/import]