Even in OpenGL, glLineWidth is wonky and may give different results on different cards for widths other than 1.
I'm pretty poor at math, but this is what I do:
//Half the width of the desired line width.
float halfWidth = (lineWidth * 0.5f);
//Set the four corners.
positionCorners[0] = lineStart + cPointF(-halfWidth, 0.0f);
positionCorners[1] = lineStart + cPointF( halfWidth, 0.0f);
positionCorners[2] = lineEnd + cPointF( halfWidth, 0.0f);
positionCorners[3] = lineEnd + cPointF(-halfWidth, 0.0f);
//Rotate the positions so they are angled (we don't want a rhombas).
float angle = cPointF::AngleBetween(lineStart, lineEnd);
cPointF::RotateAround(lineStart, angle, {positionCorners[0], positionCorners[1]});
cPointF::RotateAround(lineEnd, angle, {positionCorners[2], positionCorners[3]});
Code to RotateAround() and AngleBetween():
[spoiler]
//On a cartesian grid, centered around 'center', returns the angle (in degrees) between 12 oclock (+Y) and 'pos'.
static float AngleBetween(const Point ¢er, const Point &pos)
{
//Calculate the angle.
float radians = std::atan2(-(center.y - pos.y), -(center.x - pos.x));
//Convert to degrees, and add 90 to make 0-degrees be 12-oclock..
return RadiansToDegrees(radians) + 90;
}
//Rotate multiple points around a shared center.
static void RotateAround(const Point ¢er, float rotation, std::vector<Point> &points)
{
//Calculate and apply the rotation.
float radians = DegreesToRadians(rotation);
float cosine = std::cos(radians);
float sine = std::sin(radians);
//Rotate each point individually (but using the same cosine and sine we've already calculated).
for(auto &point : points)
{
priv_Point_RotateAround_RotatePoint(point, center, sine, cosine);
}
}
static void priv_Point_RotateAround_RotatePoint(Point &point, const Point ¢er, float sine, float cosine)
{
//Move the problem domain to make the center be (0,0), which is what we'll rotate around.
float offsetX = static_cast<float>(point.x - center.x);
float offsetY = static_cast<float>(point.y - center.y);
//Calculate the new offset.
point.x = static_cast<Point::value_type>((offsetX * cosine) - (offsetY * sine));
point.y = static_cast<Point::value_type>((offsetX * sine) + (offsetY * cosine));
//Re-apply the center to the new offset and return.
point += center;
return;
}
[/spoiler]
Basically, first I calculate this:
Then I rotate the points:
And draw it as two triangles:
I also repeat the texture, so no matter how long the line is, the texture keeps repeating (but the texture gets stretched horizontally of the line's width is larger than the texture's width - it doesn't repeat horizontally, only vertically).
It gives me good results:
That is coming from this texture: (zoomed up)