Jump to content
  • Advertisement
suliman

Pixel rounding problem... (c++)

Recommended Posts

Posted (edited)

Hi!
When drawing a part of a sprite to screen (the sprite fills up from the bottom up when 'progress' goes from 0 to 1) I can see it jump up and down slightly (i think there is some problem with rounding the pixel position).

Params in order:
posX
posY
pic (the sprite)
xStart
yStart
xEnd
yEnd

gfx.picPartRel(x,y+(1.0-progress)*pic->GetHeight()*scale,pic,0,1-progress,1,progress);

Can you see how to do this so that the image doesnt jump up and down one pixel? (it's the posY that messes it up i think due to pixel rounding).

Below is and example of drawing with progress = 0.7 (the black image is drawn from bottom up but jumps around slightly in y-position when changing progress in realtime)

image.png.279b6de135264ab5420c35855fe92f01.png

Thanks!

Edited by suliman

Share this post


Link to post
Share on other sites
Advertisement

The problem is either in the function you're calling or in the parameters you are passing into the function.

In the former case, find another function to use instead (if it's from a library) or fix the function (if it's yours).

In the latter cases, you can try rounding your progress variable to an integer number of pixels:

rounded_progress = float(int(progress*pic->GetHeight())) / pic->GetHeight();
gfx.picPartRel(x,y+(1.0-rounded_progress)*pic->GetHeight()*scale,pic,0,1-rounded_progress,1,rounded_progress);

It helps if pic->GetHeight() is a power of 2, because then the division in the rounding operation is lossless.

 

Share this post


Link to post
Share on other sites
Posted (edited)

GetHeight() doesnt return a height with a power of 2 (it can be any pixel height, in this case it's 150). However if i try it on a 128x128 sprite i get the same problem.

The code suggested doesnt solve the problem. Is there a way to evaluate which input leads to "pixel shift" and just adjust those cases with plus/minus 1 pixel?

Edited by suliman

Share this post


Link to post
Share on other sites
Posted (edited)

The problem should be related to rounding different floating point values (progress and 1-progress multiplied by some constant distance or size in pixels) to integer values, and expecting them to be matched (e.g. constant sprite size); for some values of progress they can be off by one. In other words, the unavoidable jitter becomes more troublesome because it's out of sync between parts of your scene.

A correct solution would round only one large floating point value, obtain a large integer, and add or subtract constant integers to that.

18 hours ago, a light breeze said:

In the latter cases, you can try rounding your progress variable to an integer number of pixels:


rounded_progress = float(int(progress*pic->GetHeight())) / pic->GetHeight();
gfx.picPartRel(x,y+(1.0-rounded_progress)*pic->GetHeight()*scale,pic,0,1-rounded_progress,1,rounded_progress)

This code simply replaces progress with another floating point variable rounded_progress in the same range and with the same problems. Despite the name rounded_progressI doesn't have an integer value and it cannot serve as a reference.

Unfortunately, since gfx.picPartRel() takes floating point parameters in the [0,1] range, the rounding is likely to take place there rather than in your calling code.

 

 

 

 

Edited by LorenzoGatti

Share this post


Link to post
Share on other sites
22 minutes ago, LorenzoGatti said:

This code simply replaces progress with another floating point variable rounded_progress in the same range and with the same problems. Despite the name rounded_progressI doesn't have an integer value and it cannot serve as a reference.

That's not quite the case.  There are certain numbers that can be exactly represented in a floating variable.  These include all sufficiently small integers, but also all sufficiently small fractions so long as the fraction has a power of two in its denominator.  In other words, it is possible for the called function to losslessly convert its floating point arguments back into integer coordinates.  To see this, try the following:

  1. Make sure that you have an image with power-of-two dimensions.
  2. Make sure that you use rounded_progress as defined above.
  3. Replace the picPartRel function with one that prints out the following values as floating point:
  • posX
  • posY
  • xStart * pic->GetWidth()
  • yStart * pic->GetHeight()
  • xEnd * pic->GetWidth()
  • yEnd * pic->GetHeight()

If all of the printed results are perfect integers, then you have passed in the correct parameters, which means that the problem is in the picPartRel function.  If the results are not perfect integers, then either you didn't follow all of the instructions or I made a mistake, which has been known to happen from time to time.

Share this post


Link to post
Share on other sites
13 minutes ago, suliman said:

@a light breeze

I tried that. The posY is not a perfect integer (it has decimals). The others are ok though.

Then the problem is probably with the scale variable.  If it's an integer, then my code should work.  If it's not, then I'm out of ideas.

Oh, and the x and y variables need to be integers too, but it's easy to correct them if they're not.  Just cast them to int.

Share this post


Link to post
Share on other sites

Can you explain why are you using as counterproductive a drawing call as that gfx.picPartRel?

A sane API should have parameters in pixel units: either 2 (screen position, possibly floating point) to render a whole sprite, or 6 (screen position and 4 integers) to cut an arbitrary rectangle out of a texture atlas.

If the 4 gfx.picPartRel parameters between 0 and 1 are texture coordinates, can you use texture coordinates in pixel units instead? For example, OpenGL has the ARB_texture_rectangle extension for this purpose.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!