Why is my line not straight?

I can’t figure out why one of the lines in each my buttons isn’t straight. This shows up on arm64 GNU/Linux, but not on x86_64. In this screenshot, you can see the bottom lines of the buttons rise/fall 1 pixel or so. It doesn’t look great lol.

Any ideas on why this would happen? It doesn’t happen in other apps. For example, here is the browser in which I am typing. The lines go straight across:

SDL version is 2.30.10

Here I’m printing the coordinates of the points passed to SDL_RenderDrawLines:

0: x 50, y 356
1: x 310, y 356
2: x 310, y 398
3: x 50, y 398
4: x 50, y 356

Here is the same app on x86_64 GNU/Linux, where the lines appear correctly:

EDIT: changing to SDL development tag, as this seems like a bug in SDL? Or maybe a bug in my arm64 system? (hopefully I can find a work-around either way)

If your coordinates are stored as floating-point numbers, you might want to print them with higher precision (more decimal digits) to see their true values. Maybe it’s 397.999... instead of 398 which gets truncated to 397 when you convert them to SDL_Point (which uses int) ? To fix this you might need to round your coordinates.

EDIT: SDL_RenderDrawLines doesn’t use floats so it cannot round/truncate internally but the truncation could still happen in your code when converting your float coordinates to SDL_Point.

This was a common problem in earlier versions of SDL2, but I thought it had now been fixed. This was the workaround I used:

static int renderdrawline(SDL_Renderer *renderer, int x1, int y1, int x2, int y2)
{
	int result;
	if ((x1 == x2) && (y1 == y2))
		result = SDL_RenderDrawPoint(renderer, x1, y1);
	else if (y1 == y2)
	    {
		int x;
		if (x1 > x2) { x = x1; x1 = x2; x2 = x; }
		SDL_Point *points = (SDL_Point*) malloc ((x2 - x1 + 1) * sizeof(SDL_Point));
		if (points == NULL) return -1;
		for (x = x1; x <= x2; x++)
		    {
			points[x - x1].x = x;
			points[x - x1].y = y1;
		    }
		result = SDL_RenderDrawPoints(renderer, points, x2 - x1 + 1);
		free(points);
	    }
	else if (x1 == x2)
	    {
		int y;
		if (y1 > y2) { y = y1; y1 = y2; y2 = y; }
		SDL_Point *points = (SDL_Point*) malloc ((y2 - y1 + 1) * sizeof(SDL_Point));
		if (points == NULL) return -1;
		for (y = y1; y <= y2; y++)
		    {
			points[y - y1].x = x1;
			points[y - y1].y = y;
		    }
		result = SDL_RenderDrawPoints(renderer, points, y2 - y1 + 1);
		free(points);
	    }
	else
		result = SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
	return result;
}

Nice! Thanks. I came up with a different workaround, that also seems to work, first filling a black rectangle, then filling a white rectangle 1pixel smaller on all sides:

EDIT: I had to also call SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE)

static int displayBackgroundAndBorder
(
 struct WFC_SDL_AppState* app_state,
 SDL_Rect rect,
 SDL_Color background_color) {

  /* first draw lines */
  if( 0 != SDL_SetRenderDrawColor
      (
       app_state->renderer,
       0,
       0,
       0,
       255)) {
    
    printf("setting render draw color failed\n");

    return 1;
  }

  if(0 != SDL_RenderFillRect
     (
      app_state->renderer,
      &rect)) {

    printf("Failed to draw lines\n");

    return 1;
  }

  SDL_Rect inside_rect = {
    rect.x + 1,
    rect.y + 1,
    rect.w - 2,
    rect.h - 2
  };

  if( 0 != SDL_SetRenderDrawColor
      (
       app_state->renderer,
       background_color.r,
       background_color.g,
       background_color.b,
       background_color.a)) {
    
    printf("setting render draw color failed\n");

    return 1;
  }
  
  if(0 != SDL_RenderFillRect
     (
      app_state->renderer,
      &inside_rect)) {

    printf("Failed to draw background\n");

    return 1;
  }
   
  return 0;
}

Does a rect without fill not work? (SDL_RenderDrawRect)

When I switched to SDL3 (it prefers floats) I noticed I would have minor glitches because my code assumed values would be truncated after a divide like how it does with int. If you plan on using this code with SDL3 you may want to keep that in mind