| | |
| | | #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED |
| | | |
| | | #include "SDL_hints.h" |
| | | #include "SDL_log.h" |
| | | #include "SDL_assert.h" |
| | | #include "SDL_opengl.h" |
| | | #include "../SDL_sysrender.h" |
| | | #include "SDL_shaders_gl.h" |
| | |
| | | |
| | | renderdata->glGenTextures(1, &data->utexture); |
| | | renderdata->glGenTextures(1, &data->vtexture); |
| | | renderdata->glEnable(textype); |
| | | |
| | | renderdata->glBindTexture(textype, data->utexture); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, |
| | |
| | | GL_CLAMP_TO_EDGE); |
| | | renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w+1)/2, |
| | | (texture_h+1)/2, 0, format, type, NULL); |
| | | |
| | | renderdata->glDisable(textype); |
| | | } |
| | | |
| | | if (texture->format == SDL_PIXELFORMAT_NV12 || |
| | |
| | | data->nv12 = SDL_TRUE; |
| | | |
| | | renderdata->glGenTextures(1, &data->utexture); |
| | | renderdata->glEnable(textype); |
| | | |
| | | renderdata->glBindTexture(textype, data->utexture); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, |
| | | scaleMode); |
| | |
| | | GL_CLAMP_TO_EDGE); |
| | | renderdata->glTexImage2D(textype, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2, |
| | | (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); |
| | | renderdata->glDisable(textype); |
| | | } |
| | | |
| | | return GL_CheckError("", renderer); |
| | |
| | | |
| | | renderdata->drawstate.texture = NULL; /* we trash this state. */ |
| | | |
| | | renderdata->glEnable(textype); |
| | | renderdata->glBindTexture(textype, data->texture); |
| | | renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| | | renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / texturebpp)); |
| | |
| | | (rect->w + 1)/2, (rect->h + 1)/2, |
| | | GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels); |
| | | } |
| | | renderdata->glDisable(textype); |
| | | |
| | | return GL_CheckError("glTexSubImage2D()", renderer); |
| | | } |
| | |
| | | |
| | | renderdata->drawstate.texture = NULL; /* we trash this state. */ |
| | | |
| | | renderdata->glEnable(textype); |
| | | renderdata->glBindTexture(textype, data->texture); |
| | | renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| | | renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Ypitch); |
| | |
| | | renderdata->glTexSubImage2D(textype, 0, rect->x/2, rect->y/2, |
| | | (rect->w + 1)/2, (rect->h + 1)/2, |
| | | data->format, data->formattype, Vplane); |
| | | renderdata->glDisable(textype); |
| | | |
| | | return GL_CheckError("glTexSubImage2D()", renderer); |
| | | } |
| | |
| | | GL_TextureData *data = (GL_TextureData *) texture->driverdata; |
| | | GLenum glScaleMode = (scaleMode == SDL_ScaleModeNearest) ? GL_NEAREST : GL_LINEAR; |
| | | |
| | | renderdata->glEnable(textype); |
| | | renderdata->glBindTexture(textype, data->texture); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode); |
| | | renderdata->glDisable(textype); |
| | | |
| | | if (texture->format == SDL_PIXELFORMAT_YV12 || |
| | | texture->format == SDL_PIXELFORMAT_IYUV) { |
| | | renderdata->glEnable(textype); |
| | | renderdata->glBindTexture(textype, data->utexture); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode); |
| | |
| | | renderdata->glBindTexture(textype, data->vtexture); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode); |
| | | renderdata->glDisable(textype); |
| | | } |
| | | |
| | | if (texture->format == SDL_PIXELFORMAT_NV12 || |
| | | texture->format == SDL_PIXELFORMAT_NV21) { |
| | | renderdata->glEnable(textype); |
| | | renderdata->glBindTexture(textype, data->utexture); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, glScaleMode); |
| | | renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, glScaleMode); |
| | | renderdata->glDisable(textype); |
| | | } |
| | | } |
| | | |
| | |
| | | for (i = 0; i < count; i++) { |
| | | *(verts++) = 0.5f + points[i].x; |
| | | *(verts++) = 0.5f + points[i].y; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | GL_QueueDrawLines(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count) |
| | | { |
| | | int i; |
| | | const size_t vertlen = (sizeof (GLfloat) * 2) * count; |
| | | GLfloat *verts = (GLfloat *) SDL_AllocateRenderVertices(renderer, vertlen, 0, &cmd->data.draw.first); |
| | | if (!verts) { |
| | | return -1; |
| | | } |
| | | cmd->data.draw.count = count; |
| | | |
| | | /* Offset to hit the center of the pixel. */ |
| | | for (i = 0; i < count; i++) { |
| | | *(verts++) = 0.5f + points[i].x; |
| | | *(verts++) = 0.5f + points[i].y; |
| | | } |
| | | |
| | | /* Make the last line segment one pixel longer, to satisfy the |
| | | diamond-exit rule. */ |
| | | verts -= 4; |
| | | { |
| | | const GLfloat xstart = verts[0]; |
| | | const GLfloat ystart = verts[1]; |
| | | const GLfloat xend = verts[2]; |
| | | const GLfloat yend = verts[3]; |
| | | |
| | | if (ystart == yend) { /* horizontal line */ |
| | | verts[2] += (xend > xstart) ? 1.0f : -1.0f; |
| | | } else if (xstart == xend) { /* vertical line */ |
| | | verts[3] += (yend > ystart) ? 1.0f : -1.0f; |
| | | } else { /* bump a pixel in the direction we are moving in. */ |
| | | const GLfloat deltax = xend - xstart; |
| | | const GLfloat deltay = yend - ystart; |
| | | const GLfloat angle = SDL_atan2f(deltay, deltax); |
| | | verts[2] += SDL_cosf(angle); |
| | | verts[3] += SDL_sinf(angle); |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | |
| | | 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); |
| | | 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->glBegin(GL_LINE_STRIP); |
| | | for (i = 0; i < count; ++i, verts += 2) { |
| | | data->glVertex2f(verts[0], verts[1]); |
| | | } |
| | | data->glEnd(); |
| | | break; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | |
| | | SDL_Renderer * |
| | | static SDL_Renderer * |
| | | GL_CreateRenderer(SDL_Window * window, Uint32 flags) |
| | | { |
| | | SDL_Renderer *renderer; |
| | |
| | | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RENDERER_CONTEXT_MAJOR); |
| | | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RENDERER_CONTEXT_MINOR); |
| | | |
| | | if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) { |
| | | if (SDL_RecreateWindow(window, (window_flags & ~(SDL_WINDOW_VULKAN | SDL_WINDOW_METAL)) | SDL_WINDOW_OPENGL) < 0) { |
| | | goto error; |
| | | } |
| | | } |
| | |
| | | renderer->QueueSetViewport = GL_QueueSetViewport; |
| | | renderer->QueueSetDrawColor = GL_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ |
| | | renderer->QueueDrawPoints = GL_QueueDrawPoints; |
| | | renderer->QueueDrawLines = GL_QueueDrawPoints; /* lines and points queue vertices the same way. */ |
| | | renderer->QueueDrawLines = GL_QueueDrawLines; |
| | | renderer->QueueFillRects = GL_QueueFillRects; |
| | | renderer->QueueCopy = GL_QueueCopy; |
| | | renderer->QueueCopyEx = GL_QueueCopyEx; |