diff -r 0c407e6d14a9 include/SDL_render.h --- a/include/SDL_render.h Mon Jul 25 15:03:42 2011 -0700 +++ b/include/SDL_render.h Thu Jul 28 11:38:39 2011 -0300 @@ -88,7 +88,8 @@ typedef enum { SDL_TEXTUREACCESS_STATIC, /**< Changes rarely, not lockable */ - SDL_TEXTUREACCESS_STREAMING /**< Changes frequently, lockable */ + SDL_TEXTUREACCESS_STREAMING, /**< Changes frequently, lockable */ + SDL_TEXTUREACCESS_TARGET /**< Texture can be used as a render target */ } SDL_TextureAccess; /** @@ -561,6 +562,42 @@ const SDL_Rect * srcrect, const SDL_Rect * dstrect); + +/** + * \fn SDL_bool SDL_RenderTargetSupported(SDL_Renderer *renderer) + * + * \brief Determines whether a window supports the use of render targets + * + * \param window The renderer that will be checked + * + * \return SDL_TRUE if supported, SDL_FALSE if not. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_RenderTargetSupported(SDL_Renderer *renderer); + +/** + * \fn int SDL_SetTargetTexture(SDL_TextureID textureID) + * + * \brief Set a texture as the current rendering target. + * + * \param textureId The targeted texture, or 0 to target the current window. + * + * \return 0 on success, or -1 if there is no rendering context current, or the driver doesn't support the requested operation. + */ +extern DECLSPEC int SDLCALL SDL_SetTargetTexture(SDL_Texture *texture); + +/** + * \fn SDL_bool SDL_ResetTargetTexture(SDL_Renderer *renderer) + * + * \brief Restores rendering to the default location + * + * \param renderer The renderer that will be reset + * + * \return SDL_TRUE if supported, SDL_FALSE if not. + */ +extern DECLSPEC SDL_bool SDLCALL SDL_ResetTargetTexture(SDL_Renderer *renderer); + + + /** * \brief Read pixels from the current rendering target. * diff -r 0c407e6d14a9 src/render/SDL_render.c --- a/src/render/SDL_render.c Mon Jul 25 15:03:42 2011 -0700 +++ b/src/render/SDL_render.c Thu Jul 28 11:38:39 2011 -0300 @@ -1116,6 +1116,44 @@ format, pixels, pitch); } +SDL_bool +SDL_RenderTargetSupported(SDL_Renderer *renderer) +{ + if ((!renderer) || (!renderer->SetTargetTexture)){ + return SDL_FALSE; + } + return SDL_TRUE; +} + +int +SDL_SetTargetTexture(SDL_Texture *texture) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, -1); + renderer = texture->renderer; + if ((!renderer) || (!texture)) { + return -1; + } + if (!renderer->SetTargetTexture) { + SDL_Unsupported(); + return -1; + } + return renderer->SetTargetTexture(renderer, texture); +} + +SDL_bool +SDL_ResetTargetTexture(SDL_Renderer *renderer) { + if ( !renderer || !SDL_RenderTargetSupported(renderer) ){ + return SDL_FALSE; + } + + if (renderer->SetTargetTexture(renderer, NULL) < 0) return -1; + + return 0; +} + + void SDL_RenderPresent(SDL_Renderer * renderer) { diff -r 0c407e6d14a9 src/render/SDL_sysrender.h --- a/src/render/SDL_sysrender.h Mon Jul 25 15:03:42 2011 -0700 +++ b/src/render/SDL_sysrender.h Thu Jul 28 11:38:39 2011 -0300 @@ -87,6 +87,7 @@ int count); int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect); + int (*SetTargetTexture) (SDL_Renderer * renderer, SDL_Texture * texture); int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, void * pixels, int pitch); void (*RenderPresent) (SDL_Renderer * renderer); diff -r 0c407e6d14a9 src/render/opengl/SDL_render_gl.c --- a/src/render/opengl/SDL_render_gl.c Mon Jul 25 15:03:42 2011 -0700 +++ b/src/render/opengl/SDL_render_gl.c Thu Jul 28 11:38:39 2011 -0300 @@ -66,6 +66,7 @@ const SDL_Rect * srcrect, const SDL_Rect * dstrect); static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 pixel_format, void * pixels, int pitch); +static int GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void GL_RenderPresent(SDL_Renderer * renderer); static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void GL_DestroyRenderer(SDL_Renderer * renderer); @@ -82,6 +83,15 @@ 0} }; +typedef struct GL_FBOList GL_FBOList; + +struct GL_FBOList +{ + Uint32 w, h; + GLuint FBO; + GL_FBOList *next; +}; + typedef struct { SDL_GLContext context; @@ -91,6 +101,9 @@ Uint32 color; int blendMode; } current; + + SDL_bool GL_EXT_framebuffer_object_supported; + GL_FBOList *framebuffers; /* OpenGL functions */ #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params; @@ -101,6 +114,12 @@ SDL_bool GL_ARB_multitexture_supported; PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; GLint num_texture_units; + + PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; + PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; + PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; + PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; + PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; /* Shader support */ GL_ShaderContext *shaders; @@ -123,6 +142,8 @@ SDL_bool yuv; GLuint utexture; GLuint vtexture; + + GL_FBOList *fbo; } GL_TextureData; @@ -227,6 +248,27 @@ data->glLoadIdentity(); } + +GL_FBOList * +GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h) +{ + GL_FBOList *result = data->framebuffers; + while ((result) && ((result->w != w) || (result->h != h)) ) + { + result = result->next; + } + if (result == NULL) + { + result = SDL_malloc(sizeof(GL_FBOList)); + result->w = w; + result->h = h; + data->glGenFramebuffersEXT(1, &result->FBO); + result->next = data->framebuffers; + data->framebuffers = result; + } + return result; +} + SDL_Renderer * GL_CreateRenderer(SDL_Window * window, Uint32 flags) { @@ -267,6 +309,7 @@ renderer->RenderDrawLines = GL_RenderDrawLines; renderer->RenderFillRects = GL_RenderFillRects; renderer->RenderCopy = GL_RenderCopy; + renderer->SetTargetTexture = GL_SetTargetTexture; renderer->RenderReadPixels = GL_RenderReadPixels; renderer->RenderPresent = GL_RenderPresent; renderer->DestroyTexture = GL_DestroyTexture; @@ -338,6 +381,21 @@ renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV; } + + if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) { + data->GL_EXT_framebuffer_object_supported = SDL_TRUE; + data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) + SDL_GL_GetProcAddress("glGenFramebuffersEXT"); + data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC) + SDL_GL_GetProcAddress("glDeleteFramebuffersEXT"); + data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) + SDL_GL_GetProcAddress("glFramebufferTexture2DEXT"); + data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) + SDL_GL_GetProcAddress("glBindFramebufferEXT"); + data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) + SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT"); + } + data->framebuffers = NULL; /* Set up parameters for rendering */ GL_ResetState(renderer); @@ -402,6 +460,56 @@ } static int +GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + GL_RenderData *data = (GL_RenderData *) renderer->driverdata; + int w, h; + + GL_TextureData *texturedata; + GLenum status; + + if (!renderer) return -1; + GL_ActivateRenderer(renderer); + + if (! data->GL_EXT_framebuffer_object_supported) { + SDL_Unsupported(); + return -1; + } + + if (texture == NULL) { + SDL_GetWindowSize(renderer->window, &w, &h); + data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); + data->glMatrixMode(GL_MODELVIEW); + data->glLoadIdentity(); + data->glViewport(0, 0, w, h); + data->glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 1.0); + return 0; + } + else if (renderer != texture->renderer) return -1; + + + texturedata = (GL_TextureData *) texture->driverdata; + data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO); + /* TODO: check if texture pixel format allows this operation */ + data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0); + /* Check FBO status */ + status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + return -1; + } + + data->glMatrixMode(GL_PROJECTION); + data->glLoadIdentity(); + data->glOrtho(0.0, (GLdouble) texture->w, 0.0, (GLdouble) texture->h, 0.0, 1.0); + data->glMatrixMode(GL_MODELVIEW); + data->glLoadIdentity(); + data->glViewport(0, 0, texture->w, texture->h); + return 0; +} + +static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata; @@ -445,10 +553,17 @@ } texture->driverdata = data; + + if (texture->access == SDL_TEXTUREACCESS_TARGET) { + data->fbo = GL_GetFBO(renderdata, texture->w, texture->h); + } else { + data->fbo = NULL; + } renderdata->glGetError(); renderdata->glGenTextures(1, &data->texture); - if (renderdata->GL_ARB_texture_rectangle_supported) { + if ((renderdata->GL_ARB_texture_rectangle_supported) + /*&& texture->access != SDL_TEXTUREACCESS_TARGET*/){ data->type = GL_TEXTURE_RECTANGLE_ARB; texture_w = texture->w; texture_h = texture->h; @@ -1015,6 +1130,13 @@ GL_DestroyShaderContext(data->shaders); } if (data->context) { + while (data->framebuffers) { + GL_FBOList *nextnode = data->framebuffers->next; + /* delete the framebuffer object */ + data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO); + SDL_free(data->framebuffers); + data->framebuffers = nextnode; + } /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */ SDL_GL_DeleteContext(data->context); } @@ -1026,3 +1148,6 @@ #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */ /* vi: set ts=4 sw=4 expandtab: */ +