Small aside: floats are less magical, than many people make them to be. They can be counterintuitive to unwary, but you can, in fact, ensure some things with certainty.
21 hours ago, Alberth said:
floating point is not exact, it's an approximation of the real value
I'm really not fond of that particular wording, as it conflates several issues (and in some ways is untrue).
21 hours ago, Alberth said:
For example, 1 *n + 1*n != 2*n, for many float values n.
As far as I can tell 1*n+1*n==2*n holds for all non-NaN floats.
Back to the topic at hand. Some clarifications would be welcome (e. g. drawStuff does not mention pan at all), but there seems to be enough information now to piece the problem together.
First off, if
3 hours ago, suliman said:
If i skip the remainder (% operator) all together and calc which would be the first tile shown (top left corner of the game-window) this works fine:
you may simply go with that.
Now, as to why the original code doesn't work. The reason have already been mentioned by few people, but I'll elaborate.
The lines are at
i * TILE*scale + pan.y
on the y-axis.
The first (least y) line that fits on the screen is at i=startY such that
0 <= startY * TILE*scale + pan.y < TILE*scale
-pan.y <= startY * TILE*scale < TILE*scale - pan.y
startY = ceil(- pan.y / (TILE*scale)) {assuming scale>0}
It's offset is
ceil(- pan.y / (TILE*scale)) * (TILE*scale) + pan.y
which is
-floor(pan.y / (TILE*scale)) * (TILE*scale) + pan.y
that is mod(pan.y, TILE*scale), assuming modulo is defined to be always non-negative, which std::fmod isn't.
This is different from mod((int)pan.y, (int)(TILE*scale)) which you are doing (once more, disregarding negatives).
In fact, difference can be estimated as frac(TILE*scale)*startY (not always true, since it can wrap-around), which may be quite large. This explains why integer TILE*scale work fine.
So the original code can be (I think) fixed as follows:
float oy=fmodf(pan.y,TILE*scale);
int offY = (int)(oy<0.0f?TILE*scale+oy:oy);