Problem Skinning Segmented Control

I’m using an image sheet to skin a segmented control and running into a problem – the left and right “end caps” don’t fit tight to the middle section. Here’s a pic:

iosilversegmentbug.png

You can see the lines in the circled areas on both sides.

I’ve triple-checked my code, as well as the image sheet created by TexturePacker and can’t find anything wrong. The lines stay there no matter which segment is chosen.

Anybody run into anything like this before?

 Jay

Hi Jay,

Can you please post your code, including the setup of the image sheet which you’re using, so I can see the sizes of each part?

Thanks,

Brent

This code run as main.lua shows the problem (if you have the correct graphics, anyway):

local widget = require("widget") local options = { frames = { { x=0, y=40, width=15, height=40 }, { x=30, y=0, width=15, height=40 }, { x=0, y=0, width=15, height=40 }, { x=15, y=40, width=15, height=40 }, { x=45, y=0, width=15, height=40 }, { x=15, y=0, width=15, height=40 }, { x=30, y=40, width=6, height=40 } }, sheetContentWidth = 64, sheetContentHeight = 128 } local segmentSheet = graphics.newImageSheet( "SegmentedControl.png", options ) local segmentedControl = widget.newSegmentedControl { x = display.contentCenterX, y = 85, segmentWidth = 120, segments = { "Arcade", "Strategy" }, defaultSegment = def, labelSize=20, labelColor = { default={ 0.5, 0.5, 0.5 }, over={ 1, 1, 1 } }, sheet = segmentSheet, leftSegmentFrame = 1, middleSegmentFrame = 2, rightSegmentFrame = 3, leftSegmentSelectedFrame = 4, middleSegmentSelectedFrame = 5, rightSegmentSelectedFrame = 6, segmentFrameWidth = 15, segmentFrameHeight = 40, }

If you want a project consisting of that file plus the graphics, here it is:

http://gamedevnation.com/files/SegControlProblem.zip

Thanks.

 Jay

Any ideas on this?

 Jay

Hi Jay,

Your image sheet should be a continuous bar.

I attached a modified image.

So, your image declaration should be as follows.

-- Image sheet options and declaration local options = { frames = { { x=0, y=0, width=15, height=40 }, { x=15, y=0, width=15, height=40 }, { x=30, y=0, width=15, height=40 }, { x=0, y=40, width=15, height=40 }, { x=15, y=40, width=15, height=40 }, { x=30, y=40, width=15, height=40 }, { x=45, y=40, width=6, height=40 } }, sheetContentWidth = 64, sheetContentHeight = 128 } local segmentSheet = graphics.newImageSheet( "SegmentedControl.png", options )

Good Luck!

burhan

Thanks, burhan, that fixes my problem – but an image sheet should be able to be “scrambled” so it looks like a bug to me.

Is that correct, Brent?

 Jay

Hi Jay,

Let me take a look at your project tomorrow… it was (is) the holidays so we’re taking a little time off, but I’ll be able to check out your project soon.

Thanks,

Brent

Hi Jay,

What’s happening in your original image sheet (before Burhan modified it) isn’t a bug, but rather a factor of how image sheets and OpenGL textures work. When you pull a frame from an image sheet, like the middle section of your segmented control, and then you stretch that frame out in your code to a size that’s a fair amount larger than the pixels of the actual frame on the sheet, the neighboring pixels (of the frames beside it) can be pulled in somewhat and become part of that frame on the outer edges. So, because you placed the green segment next to the black segment in your original sheet, some of the black is “bleeding” into the green when you stretch out that green middle segment for the segmented control widget.

Fortunately, the solution to this isn’t complicated once you know what’s happening. Usually the best way, when you’re using a frame that  will repeat/stretch horizontally (or vertically), is to make that frame wider/taller on the sheet, with the same visual content padding out a few pixels on either side. So, for example, you could pull 15 pixels of the middle green section from the sheet, but on the sheet, add 2 pixels of the same visual appearance on either side (so, 19 pixels in total, but you’re only pulling off 15 of that). Another option is to make the middle frame much wider, and closer in overall size to what the actual segment width will be on your segmented control… that will usually minimize the bleeding factor, but it will also require a larger image sheet, so I prefer the first option.

Hope this helps,

Brent

Thanks for the explanation, Brent, but it still sounds like a bug. Why would any stretching be done before the frame was grabbed? If a frame is specified, why would surrounding areas be grabbed? Is it a bug in OpenGL?

I’d think the frame would be grabbed (and only the area specified) and then any needed resizing would be done on that image part. 

 Jay

Hi Jay,

Well, the deep technical OpenGL explanation of this is beyond my knowledge, but I think you could research it (if so inclined) and look for how it treats textures. You’ll notice that this issue extends to OpenGL in general, and packing programs like TexturePacker offer the ability to pad frames with transparent pixels specifically so that neighboring frame content doesn’t bleed into other frames.

Brent

Hi Jay,

Can you please post your code, including the setup of the image sheet which you’re using, so I can see the sizes of each part?

Thanks,

Brent

This code run as main.lua shows the problem (if you have the correct graphics, anyway):

local widget = require("widget") local options = { frames = { { x=0, y=40, width=15, height=40 }, { x=30, y=0, width=15, height=40 }, { x=0, y=0, width=15, height=40 }, { x=15, y=40, width=15, height=40 }, { x=45, y=0, width=15, height=40 }, { x=15, y=0, width=15, height=40 }, { x=30, y=40, width=6, height=40 } }, sheetContentWidth = 64, sheetContentHeight = 128 } local segmentSheet = graphics.newImageSheet( "SegmentedControl.png", options ) local segmentedControl = widget.newSegmentedControl { x = display.contentCenterX, y = 85, segmentWidth = 120, segments = { "Arcade", "Strategy" }, defaultSegment = def, labelSize=20, labelColor = { default={ 0.5, 0.5, 0.5 }, over={ 1, 1, 1 } }, sheet = segmentSheet, leftSegmentFrame = 1, middleSegmentFrame = 2, rightSegmentFrame = 3, leftSegmentSelectedFrame = 4, middleSegmentSelectedFrame = 5, rightSegmentSelectedFrame = 6, segmentFrameWidth = 15, segmentFrameHeight = 40, }

If you want a project consisting of that file plus the graphics, here it is:

http://gamedevnation.com/files/SegControlProblem.zip

Thanks.

 Jay

Any ideas on this?

 Jay

Hi Jay,

Your image sheet should be a continuous bar.

I attached a modified image.

So, your image declaration should be as follows.

-- Image sheet options and declaration local options = { frames = { { x=0, y=0, width=15, height=40 }, { x=15, y=0, width=15, height=40 }, { x=30, y=0, width=15, height=40 }, { x=0, y=40, width=15, height=40 }, { x=15, y=40, width=15, height=40 }, { x=30, y=40, width=15, height=40 }, { x=45, y=40, width=6, height=40 } }, sheetContentWidth = 64, sheetContentHeight = 128 } local segmentSheet = graphics.newImageSheet( "SegmentedControl.png", options )

Good Luck!

burhan

Thanks, burhan, that fixes my problem – but an image sheet should be able to be “scrambled” so it looks like a bug to me.

Is that correct, Brent?

 Jay

Hi Jay,

Let me take a look at your project tomorrow… it was (is) the holidays so we’re taking a little time off, but I’ll be able to check out your project soon.

Thanks,

Brent

Hi Jay,

What’s happening in your original image sheet (before Burhan modified it) isn’t a bug, but rather a factor of how image sheets and OpenGL textures work. When you pull a frame from an image sheet, like the middle section of your segmented control, and then you stretch that frame out in your code to a size that’s a fair amount larger than the pixels of the actual frame on the sheet, the neighboring pixels (of the frames beside it) can be pulled in somewhat and become part of that frame on the outer edges. So, because you placed the green segment next to the black segment in your original sheet, some of the black is “bleeding” into the green when you stretch out that green middle segment for the segmented control widget.

Fortunately, the solution to this isn’t complicated once you know what’s happening. Usually the best way, when you’re using a frame that  will repeat/stretch horizontally (or vertically), is to make that frame wider/taller on the sheet, with the same visual content padding out a few pixels on either side. So, for example, you could pull 15 pixels of the middle green section from the sheet, but on the sheet, add 2 pixels of the same visual appearance on either side (so, 19 pixels in total, but you’re only pulling off 15 of that). Another option is to make the middle frame much wider, and closer in overall size to what the actual segment width will be on your segmented control… that will usually minimize the bleeding factor, but it will also require a larger image sheet, so I prefer the first option.

Hope this helps,

Brent

Thanks for the explanation, Brent, but it still sounds like a bug. Why would any stretching be done before the frame was grabbed? If a frame is specified, why would surrounding areas be grabbed? Is it a bug in OpenGL?

I’d think the frame would be grabbed (and only the area specified) and then any needed resizing would be done on that image part. 

 Jay

Hi Jay,

Well, the deep technical OpenGL explanation of this is beyond my knowledge, but I think you could research it (if so inclined) and look for how it treats textures. You’ll notice that this issue extends to OpenGL in general, and packing programs like TexturePacker offer the ability to pad frames with transparent pixels specifically so that neighboring frame content doesn’t bleed into other frames.

Brent