Skip to content

Commit

Permalink
opengl: Backed out hg changeset 94f9f40a957f
Browse files Browse the repository at this point in the history
This is the OpenGL line drawing fix for Bugzilla #3182, but there's some
disagreement about what the renderers should do here, so I'm backing this out
until after 2.0.12 ships, and then we'll reevaluate all the renderer backends
to decide what's correct, and make them all work the same.
  • Loading branch information
icculus committed Feb 17, 2020
1 parent 1b82606 commit 93b26f1
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 175 deletions.
113 changes: 52 additions & 61 deletions src/render/opengl/SDL_render_gl.c
Expand Up @@ -865,60 +865,6 @@ GL_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FP
return 0;
}

static int
GL_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
GLfloat *verts;
int i;

SDL_assert(count >= 2); /* should have been checked at the higher level. */

verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, (count-1) * 4 * sizeof (GLfloat), 0, &cmd->data.draw.first);
if (!verts) {
return -1;
}

cmd->data.draw.count = count;

/* GL_LINE_STRIP seems to be unreliable on various drivers, so try
to build out our own GL_LINES. :(
If the line segment is completely horizontal or vertical,
make it one pixel longer, to satisfy the diamond-exit rule.
We should probably do this for diagonal lines too, but we'd have to
do some trigonometry to figure out the correct pixel and generally
when we have problems with pixel perfection, it's for straight lines
that are missing a pixel that frames something and not arbitrary
angles. Maybe !!! FIXME for later, though. */

for (i = 0; i < count-1; i++, points++) {
GLfloat xstart = 0.5f + points[0].x; /* 0.5f to get to the center of the pixel. */
GLfloat ystart = 0.5f + points[0].y;
GLfloat xend = 0.5f + points[1].x;
GLfloat yend = 0.5f + points[1].y;

if (xstart == xend) { /* vertical line */
if (yend > ystart) {
yend += 1.0f;
} else {
ystart += 1.0f;
}
} else if (ystart == yend) { /* horizontal line */
if (xend > xstart) {
xend += 1.0f;
} else {
xstart += 1.0f;
}
}

*(verts++) = xstart;
*(verts++) = ystart;
*(verts++) = xend;
*(verts++) = yend;
}

return 0;
}

static int
GL_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
Expand Down Expand Up @@ -1282,14 +1228,59 @@ GL_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertic
case SDL_RENDERCMD_DRAW_LINES: {
const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
const size_t count = cmd->data.draw.count;
SDL_assert(count >= 2);
SetDrawState(data, cmd, SHADER_SOLID);
data->glBegin(GL_LINES);
for (i = 0; i < count-1; ++i, verts += 4) {
data->glVertex2f(verts[0], verts[1]);
data->glVertex2f(verts[2], verts[3]);
if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
data->glBegin(GL_LINE_LOOP);
/* GL_LINE_LOOP takes care of the final segment */
for (i = 1; i < count; ++i, verts += 2) {
data->glVertex2f(verts[0], verts[1]);
}
data->glEnd();
} else {
#if defined(__MACOSX__) || defined(__WIN32__)
#else
int x1, y1, x2, y2;
#endif

data->glBegin(GL_LINE_STRIP);
for (i = 0; i < count; ++i, verts += 2) {
data->glVertex2f(verts[0], verts[1]);
}
data->glEnd();
verts -= 2 * count;

/* The line is half open, so we need one more point to complete it.
* http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
* If we have to, we can use vertical line and horizontal line textures
* for vertical and horizontal lines, and then create custom textures
* for diagonal lines and software render those. It's terrible, but at
* least it would be pixel perfect.
*/

data->glBegin(GL_POINTS);
#if defined(__MACOSX__) || defined(__WIN32__)
/* Mac OS X and Windows seem to always leave the last point open */
data->glVertex2f(verts[(count-1)*2], verts[(count*2)-1]);
#else
/* Linux seems to leave the right-most or bottom-most point open */
x1 = verts[0];
y1 = verts[1];
x2 = verts[(count-1)*2];
y2 = verts[(count*2)-1];

if (x1 > x2) {
data->glVertex2f(x1, y1);
} else if (x2 > x1) {
data->glVertex2f(x2, y2);
}
if (y1 > y2) {
data->glVertex2f(x1, y1);
} else if (y2 > y1) {
data->glVertex2f(x2, y2);
}
#endif
data->glEnd();
}
data->glEnd();
break;
}

Expand Down Expand Up @@ -1628,7 +1619,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = GL_QueueSetViewport;
renderer->QueueSetDrawColor = GL_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = GL_QueueDrawPoints;
renderer->QueueDrawLines = GL_QueueDrawLines;
renderer->QueueDrawLines = GL_QueueDrawPoints; /* lines and points queue vertices the same way. */
renderer->QueueFillRects = GL_QueueFillRects;
renderer->QueueCopy = GL_QueueCopy;
renderer->QueueCopyEx = GL_QueueCopyEx;
Expand Down
66 changes: 9 additions & 57 deletions src/render/opengles/SDL_render_gles.c
Expand Up @@ -561,60 +561,6 @@ GLES_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_
return 0;
}

static int
GLES_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
GLfloat *verts;
int i;

SDL_assert(count >= 2); /* should have been checked at the higher level. */

verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, (count-1) * 4 * sizeof (GLfloat), 0, &cmd->data.draw.first);
if (!verts) {
return -1;
}

cmd->data.draw.count = count;

/* GL_LINE_STRIP seems to be unreliable on various drivers, so try
to build out our own GL_LINES. :(
If the line segment is completely horizontal or vertical,
make it one pixel longer, to satisfy the diamond-exit rule.
We should probably do this for diagonal lines too, but we'd have to
do some trigonometry to figure out the correct pixel and generally
when we have problems with pixel perfection, it's for straight lines
that are missing a pixel that frames something and not arbitrary
angles. Maybe !!! FIXME for later, though. */

for (i = 0; i < count-1; i++, points++) {
GLfloat xstart = 0.5f + points[0].x; /* 0.5f to get to the center of the pixel. */
GLfloat ystart = 0.5f + points[0].y;
GLfloat xend = 0.5f + points[1].x;
GLfloat yend = 0.5f + points[1].y;

if (xstart == xend) { /* vertical line */
if (yend > ystart) {
yend += 1.0f;
} else {
ystart += 1.0f;
}
} else if (ystart == yend) { /* horizontal line */
if (xend > xstart) {
xend += 1.0f;
} else {
xstart += 1.0f;
}
}

*(verts++) = xstart;
*(verts++) = ystart;
*(verts++) = xend;
*(verts++) = yend;
}

return 0;
}

static int
GLES_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
Expand Down Expand Up @@ -955,10 +901,16 @@ GLES_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vert
case SDL_RENDERCMD_DRAW_LINES: {
const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
const size_t count = cmd->data.draw.count;
SDL_assert(count >= 2);
SetDrawState(data, cmd);
data->glVertexPointer(2, GL_FLOAT, 0, verts);
data->glDrawArrays(GL_LINES, 0, (GLsizei) ((count-1) * 2));
if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
/* GL_LINE_LOOP takes care of the final segment */
data->glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) (count - 1));
} else {
data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
/* We need to close the endpoint of the line */
data->glDrawArrays(GL_POINTS, (GLsizei) (count - 1), 1);
}
break;
}

Expand Down Expand Up @@ -1207,7 +1159,7 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->QueueSetViewport = GLES_QueueSetViewport;
renderer->QueueSetDrawColor = GLES_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = GLES_QueueDrawPoints;
renderer->QueueDrawLines = GLES_QueueDrawLines;
renderer->QueueDrawLines = GLES_QueueDrawPoints; /* lines and points queue vertices the same way. */
renderer->QueueFillRects = GLES_QueueFillRects;
renderer->QueueCopy = GLES_QueueCopy;
renderer->QueueCopyEx = GLES_QueueCopyEx;
Expand Down
67 changes: 10 additions & 57 deletions src/render/opengles2/SDL_render_gles2.c
Expand Up @@ -783,60 +783,6 @@ GLES2_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL
return 0;
}

static int
GLES2_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
{
GLfloat *verts;
int i;

SDL_assert(count >= 2); /* should have been checked at the higher level. */

verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, (count-1) * 4 * sizeof (GLfloat), 0, &cmd->data.draw.first);
if (!verts) {
return -1;
}

cmd->data.draw.count = count;

/* GL_LINE_STRIP seems to be unreliable on various drivers, so try
to build out our own GL_LINES. :(
If the line segment is completely horizontal or vertical,
make it one pixel longer, to satisfy the diamond-exit rule.
We should probably do this for diagonal lines too, but we'd have to
do some trigonometry to figure out the correct pixel and generally
when we have problems with pixel perfection, it's for straight lines
that are missing a pixel that frames something and not arbitrary
angles. Maybe !!! FIXME for later, though. */

for (i = 0; i < count-1; i++, points++) {
GLfloat xstart = 0.5f + points[0].x; /* 0.5f to get to the center of the pixel. */
GLfloat ystart = 0.5f + points[0].y;
GLfloat xend = 0.5f + points[1].x;
GLfloat yend = 0.5f + points[1].y;

if (xstart == xend) { /* vertical line */
if (yend > ystart) {
yend += 1.0f;
} else {
ystart += 1.0f;
}
} else if (ystart == yend) { /* horizontal line */
if (xend > xstart) {
xend += 1.0f;
} else {
xstart += 1.0f;
}
}

*(verts++) = xstart;
*(verts++) = ystart;
*(verts++) = xend;
*(verts++) = yend;
}

return 0;
}

static int
GLES2_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
{
Expand Down Expand Up @@ -1348,10 +1294,17 @@ GLES2_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *ver
}

case SDL_RENDERCMD_DRAW_LINES: {
const GLfloat *verts = (GLfloat *) (((Uint8 *) vertices) + cmd->data.draw.first);
const size_t count = cmd->data.draw.count;
SDL_assert(count >= 2);
if (SetDrawState(data, cmd, GLES2_IMAGESOURCE_SOLID) == 0) {
data->glDrawArrays(GL_LINES, 0, (GLsizei) ((count-1) * 2));
if (count > 2 && (verts[0] == verts[(count-1)*2]) && (verts[1] == verts[(count*2)-1])) {
/* GL_LINE_LOOP takes care of the final segment */
data->glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) (count - 1));
} else {
data->glDrawArrays(GL_LINE_STRIP, 0, (GLsizei) count);
/* We need to close the endpoint of the line */
data->glDrawArrays(GL_POINTS, (GLsizei) (count - 1), 1);
}
}
break;
}
Expand Down Expand Up @@ -2146,7 +2099,7 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
renderer->QueueSetViewport = GLES2_QueueSetViewport;
renderer->QueueSetDrawColor = GLES2_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
renderer->QueueDrawPoints = GLES2_QueueDrawPoints;
renderer->QueueDrawLines = GLES2_QueueDrawLines;
renderer->QueueDrawLines = GLES2_QueueDrawPoints; /* lines and points queue vertices the same way. */
renderer->QueueFillRects = GLES2_QueueFillRects;
renderer->QueueCopy = GLES2_QueueCopy;
renderer->QueueCopyEx = GLES2_QueueCopyEx;
Expand Down

0 comments on commit 93b26f1

Please sign in to comment.