Implementation of render targets, by Mason Wheeler and Gabriel Jacobo
authorSam Lantinga <slouken@libsdl.org>
Wed, 18 Jan 2012 22:45:49 -0500
changeset 623237e8d0736366
parent 6231 5eecf59b698f
child 6235 d169541f5049
Implementation of render targets, by Mason Wheeler and Gabriel Jacobo

Thanks guys!
include/SDL_render.h
src/render/SDL_render.c
src/render/SDL_sysrender.h
src/render/direct3d/SDL_render_d3d.c
src/render/opengl/SDL_render_gl.c
src/render/opengles/SDL_glesfuncs.h
src/render/opengles/SDL_render_gles.c
src/render/opengles2/SDL_gles2funcs.h
src/render/opengles2/SDL_render_gles2.c
test/Makefile.in
test/testrendertarget.c
     1.1 --- a/include/SDL_render.h	Wed Jan 18 22:22:54 2012 -0500
     1.2 +++ b/include/SDL_render.h	Wed Jan 18 22:45:49 2012 -0500
     1.3 @@ -88,7 +88,8 @@
     1.4  typedef enum
     1.5  {
     1.6      SDL_TEXTUREACCESS_STATIC,    /**< Changes rarely, not lockable */
     1.7 -    SDL_TEXTUREACCESS_STREAMING  /**< Changes frequently, lockable */
     1.8 +    SDL_TEXTUREACCESS_STREAMING, /**< Changes frequently, lockable */
     1.9 +    SDL_TEXTUREACCESS_TARGET     /**< Texture can be used as a render target */
    1.10  } SDL_TextureAccess;
    1.11  
    1.12  /**
    1.13 @@ -561,6 +562,31 @@
    1.14                                             const SDL_Rect * srcrect,
    1.15                                             const SDL_Rect * dstrect);
    1.16  
    1.17 +
    1.18 +/**
    1.19 + * \fn SDL_bool SDL_RenderTargetSupported(SDL_Renderer *renderer)
    1.20 + *
    1.21 + * \brief Determines whether a window supports the use of render targets
    1.22 + *
    1.23 + * \param renderer The renderer that will be checked
    1.24 + *
    1.25 + * \return SDL_TRUE if supported, SDL_FALSE if not.
    1.26 + */
    1.27 +extern DECLSPEC SDL_bool SDLCALL SDL_RenderTargetSupported(SDL_Renderer *renderer);
    1.28 +
    1.29 +/**
    1.30 + * \fn int SDL_SetTargetTexture(SDL_Renderer *renderer, SDL_Texture *texture)
    1.31 + *
    1.32 + * \brief Set a texture as the current rendering target.
    1.33 + *
    1.34 + * \param renderer The renderer that will be checked
    1.35 + *
    1.36 + * \param texture The targeted texture, or NULL for the default render target
    1.37 + *
    1.38 + * \return 0 on success, or -1 if there is no rendering context current, or the driver doesn't support the requested operation.
    1.39 + */
    1.40 +extern DECLSPEC int SDLCALL SDL_SetTargetTexture(SDL_Renderer *renderer, SDL_Texture *texture);
    1.41 +
    1.42  /**
    1.43   *  \brief Read pixels from the current rendering target.
    1.44   *  
     2.1 --- a/src/render/SDL_render.c	Wed Jan 18 22:22:54 2012 -0500
     2.2 +++ b/src/render/SDL_render.c	Wed Jan 18 22:45:49 2012 -0500
     2.3 @@ -1014,9 +1014,9 @@
     2.4  SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
     2.5  {
     2.6      SDL_Rect full_rect;
     2.7 -	
     2.8 +
     2.9      CHECK_RENDERER_MAGIC(renderer, -1);
    2.10 -	
    2.11 +
    2.12      /* If 'rect' == NULL, then outline the whole surface */
    2.13      if (!rect) {
    2.14          full_rect.x = 0;
    2.15 @@ -1150,6 +1150,35 @@
    2.16                                        format, pixels, pitch);
    2.17  }
    2.18  
    2.19 +SDL_bool
    2.20 +SDL_RenderTargetSupported(SDL_Renderer *renderer)
    2.21 +{
    2.22 +    if ((!renderer) || (!renderer->SetTargetTexture)) {
    2.23 +        return SDL_FALSE;
    2.24 +    }
    2.25 +    return SDL_TRUE;
    2.26 +}
    2.27 +
    2.28 +int
    2.29 +SDL_SetTargetTexture(SDL_Renderer *renderer, SDL_Texture *texture)
    2.30 +{
    2.31 +    
    2.32 +    if(!renderer) {
    2.33 +        return -1;
    2.34 +    }
    2.35 +    if (!renderer->SetTargetTexture) {
    2.36 +        SDL_Unsupported();
    2.37 +        return -1;
    2.38 +    }
    2.39 +    // Warning: texture==NULL is a valid parameter
    2.40 +    if( texture ) {
    2.41 +        CHECK_TEXTURE_MAGIC(texture, -1);
    2.42 +        if(renderer != texture->renderer) return -1;
    2.43 +    }
    2.44 +    
    2.45 +    return renderer->SetTargetTexture(renderer, texture);
    2.46 +}
    2.47 +
    2.48  void
    2.49  SDL_RenderPresent(SDL_Renderer * renderer)
    2.50  {
     3.1 --- a/src/render/SDL_sysrender.h	Wed Jan 18 22:22:54 2012 -0500
     3.2 +++ b/src/render/SDL_sysrender.h	Wed Jan 18 22:45:49 2012 -0500
     3.3 @@ -87,6 +87,7 @@
     3.4                              int count);
     3.5      int (*RenderCopy) (SDL_Renderer * renderer, SDL_Texture * texture,
     3.6                         const SDL_Rect * srcrect, const SDL_Rect * dstrect);
     3.7 +    int (*SetTargetTexture) (SDL_Renderer * renderer, SDL_Texture * texture);
     3.8      int (*RenderReadPixels) (SDL_Renderer * renderer, const SDL_Rect * rect,
     3.9                               Uint32 format, void * pixels, int pitch);
    3.10      void (*RenderPresent) (SDL_Renderer * renderer);
     4.1 --- a/src/render/direct3d/SDL_render_d3d.c	Wed Jan 18 22:22:54 2012 -0500
     4.2 +++ b/src/render/direct3d/SDL_render_d3d.c	Wed Jan 18 22:45:49 2012 -0500
     4.3 @@ -111,6 +111,7 @@
     4.4                            const SDL_Rect * srcrect, const SDL_Rect * dstrect);
     4.5  static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
     4.6                                  Uint32 format, void * pixels, int pitch);
     4.7 +static int D3D_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
     4.8  static void D3D_RenderPresent(SDL_Renderer * renderer);
     4.9  static void D3D_DestroyTexture(SDL_Renderer * renderer,
    4.10                                 SDL_Texture * texture);
    4.11 @@ -138,6 +139,12 @@
    4.12      SDL_bool updateSize;
    4.13      SDL_bool beginScene;
    4.14      D3DTEXTUREFILTERTYPE scaleMode;
    4.15 +    IDirect3DSurface9 *defaultRenderTarget;
    4.16 +    IDirect3DSurface9 *currentRenderTarget;
    4.17 +    SDL_bool renderTargetActive;
    4.18 +    SDL_Rect viewport_copy;
    4.19 +    
    4.20 +    Uint32 NumSimultaneousRTs;
    4.21  } D3D_RenderData;
    4.22  
    4.23  typedef struct
    4.24 @@ -392,6 +399,7 @@
    4.25      renderer->RenderFillRects = D3D_RenderFillRects;
    4.26      renderer->RenderCopy = D3D_RenderCopy;
    4.27      renderer->RenderReadPixels = D3D_RenderReadPixels;
    4.28 +    renderer->SetTargetTexture = D3D_SetTargetTexture;
    4.29      renderer->RenderPresent = D3D_RenderPresent;
    4.30      renderer->DestroyTexture = D3D_DestroyTexture;
    4.31      renderer->DestroyRenderer = D3D_DestroyRenderer;
    4.32 @@ -478,6 +486,7 @@
    4.33      IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
    4.34      renderer->info.max_texture_width = caps.MaxTextureWidth;
    4.35      renderer->info.max_texture_height = caps.MaxTextureHeight;
    4.36 +    data->NumSimultaneousRTs = caps.NumSimultaneousRTs;
    4.37  
    4.38      /* Set up parameters for rendering */
    4.39      IDirect3DDevice9_SetVertexShader(data->device, NULL);
    4.40 @@ -507,6 +516,11 @@
    4.41      IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP,
    4.42                                            D3DTOP_DISABLE);
    4.43  
    4.44 +    /* Store the default render target */
    4.45 +    IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget );
    4.46 +    data->currentRenderTarget = NULL;
    4.47 +    data->renderTargetActive = SDL_FALSE;
    4.48 +
    4.49      /* Set an identity world and view matrix */
    4.50      matrix.m[0][0] = 1.0f;
    4.51      matrix.m[0][1] = 0.0f;
    4.52 @@ -555,6 +569,80 @@
    4.53  }
    4.54  
    4.55  static int
    4.56 +D3D_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
    4.57 +{
    4.58 +    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
    4.59 +    D3D_TextureData *texturedata;
    4.60 +    HRESULT result;
    4.61 +
    4.62 +    if (!renderer) return -1;
    4.63 +    D3D_ActivateRenderer(renderer);
    4.64 +
    4.65 +    if (data->NumSimultaneousRTs < 2) {
    4.66 +        SDL_Unsupported();
    4.67 +        return -1;
    4.68 +    }
    4.69 +
    4.70 +    // Release the previous render target if it wasn't the default one
    4.71 +    if (data->currentRenderTarget != NULL) {
    4.72 +        IDirect3DSurface9_Release(data->currentRenderTarget);
    4.73 +        data->currentRenderTarget = NULL;
    4.74 +    }
    4.75 +
    4.76 +    /* Prepare an identity world and view matrix */
    4.77 +    D3DMATRIX matrix;
    4.78 +    matrix.m[0][0] = 1.0f;
    4.79 +    matrix.m[0][1] = 0.0f;
    4.80 +    matrix.m[0][2] = 0.0f;
    4.81 +    matrix.m[0][3] = 0.0f;
    4.82 +    matrix.m[1][0] = 0.0f;
    4.83 +    matrix.m[1][1] = 1.0f;
    4.84 +    matrix.m[1][2] = 0.0f;
    4.85 +    matrix.m[1][3] = 0.0f;
    4.86 +    matrix.m[2][0] = 0.0f;
    4.87 +    matrix.m[2][1] = 0.0f;
    4.88 +    matrix.m[2][2] = 1.0f;
    4.89 +    matrix.m[2][3] = 0.0f;
    4.90 +    matrix.m[3][0] = 0.0f;
    4.91 +    matrix.m[3][1] = 0.0f;
    4.92 +    matrix.m[3][2] = 0.0f;
    4.93 +    matrix.m[3][3] = 1.0f;
    4.94 +
    4.95 +    if (texture == NULL) {
    4.96 +        if (data->renderTargetActive) {
    4.97 +            data->renderTargetActive = SDL_FALSE;
    4.98 +            IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget );
    4.99 +            renderer->viewport = data->viewport_copy;
   4.100 +            D3D_UpdateViewport(renderer);
   4.101 +        }
   4.102 +        return 0;
   4.103 +    }
   4.104 +    if (renderer != texture->renderer) return -1;
   4.105 +
   4.106 +    if ( !data->renderTargetActive ) {
   4.107 +        data->viewport_copy = renderer->viewport;
   4.108 +    }
   4.109 +
   4.110 +    texturedata = (D3D_TextureData *) texture->driverdata;
   4.111 +    result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture, 0, &data->currentRenderTarget );
   4.112 +    if(FAILED(result)) {
   4.113 +        return -1;
   4.114 +    }
   4.115 +    result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget );
   4.116 +    if(FAILED(result)) {
   4.117 +        return -1;
   4.118 +    }
   4.119 +
   4.120 +    data->renderTargetActive = SDL_TRUE;
   4.121 +    renderer->viewport.x = 0;
   4.122 +    renderer->viewport.y = 0;
   4.123 +    renderer->viewport.w = texture->w;
   4.124 +    renderer->viewport.h = texture->h;
   4.125 +    D3D_UpdateViewport(renderer);
   4.126 +    return 0;
   4.127 +}
   4.128 +
   4.129 +static int
   4.130  D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   4.131  {
   4.132      D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
   4.133 @@ -580,6 +668,11 @@
   4.134          usage = D3DUSAGE_DYNAMIC;
   4.135      } else
   4.136  #endif
   4.137 +    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   4.138 +        pool = D3DPOOL_DEFAULT;         // D3DPOOL_MANAGED does not work with usage=D3DUSAGE_RENDERTARGET
   4.139 +        usage = D3DUSAGE_RENDERTARGET;
   4.140 +    }
   4.141 +    else
   4.142      {
   4.143          pool = D3DPOOL_MANAGED;
   4.144          usage = 0;
   4.145 @@ -1187,6 +1280,13 @@
   4.146      D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
   4.147  
   4.148      if (data) {
   4.149 +        // Release the render target
   4.150 +        IDirect3DSurface9_Release(data->defaultRenderTarget);
   4.151 +        if (data->currentRenderTarget != NULL) {
   4.152 +            IDirect3DSurface9_Release(data->currentRenderTarget);
   4.153 +            data->currentRenderTarget = NULL;
   4.154 +        }
   4.155 +        
   4.156          if (data->device) {
   4.157              IDirect3DDevice9_Release(data->device);
   4.158          }
     5.1 --- a/src/render/opengl/SDL_render_gl.c	Wed Jan 18 22:22:54 2012 -0500
     5.2 +++ b/src/render/opengl/SDL_render_gl.c	Wed Jan 18 22:45:49 2012 -0500
     5.3 @@ -66,6 +66,7 @@
     5.4                           const SDL_Rect * srcrect, const SDL_Rect * dstrect);
     5.5  static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
     5.6                                 Uint32 pixel_format, void * pixels, int pitch);
     5.7 +static int GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
     5.8  static void GL_RenderPresent(SDL_Renderer * renderer);
     5.9  static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    5.10  static void GL_DestroyRenderer(SDL_Renderer * renderer);
    5.11 @@ -82,6 +83,15 @@
    5.12       0}
    5.13  };
    5.14  
    5.15 +typedef struct GL_FBOList GL_FBOList;
    5.16 +
    5.17 +struct GL_FBOList
    5.18 +{
    5.19 +    Uint32 w, h;
    5.20 +    GLuint FBO;
    5.21 +    GL_FBOList *next;
    5.22 +};
    5.23 +
    5.24  typedef struct
    5.25  {
    5.26      SDL_GLContext context;
    5.27 @@ -91,6 +101,11 @@
    5.28          Uint32 color;
    5.29          int blendMode;
    5.30      } current;
    5.31 +    
    5.32 +    SDL_bool GL_EXT_framebuffer_object_supported;
    5.33 +    GL_FBOList *framebuffers;
    5.34 +    SDL_Texture *renderTarget;
    5.35 +    SDL_Rect viewport_copy;
    5.36  
    5.37      /* OpenGL functions */
    5.38  #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
    5.39 @@ -101,6 +116,12 @@
    5.40      SDL_bool GL_ARB_multitexture_supported;
    5.41      PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
    5.42      GLint num_texture_units;
    5.43 +    
    5.44 +    PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
    5.45 +    PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
    5.46 +    PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
    5.47 +    PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
    5.48 +    PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
    5.49  
    5.50      /* Shader support */
    5.51      GL_ShaderContext *shaders;
    5.52 @@ -123,6 +144,8 @@
    5.53      SDL_bool yuv;
    5.54      GLuint utexture;
    5.55      GLuint vtexture;
    5.56 +    
    5.57 +    GL_FBOList *fbo;
    5.58  } GL_TextureData;
    5.59  
    5.60  
    5.61 @@ -227,6 +250,29 @@
    5.62      data->glLoadIdentity();
    5.63  }
    5.64  
    5.65 +
    5.66 +GL_FBOList *
    5.67 +GL_GetFBO(GL_RenderData *data, Uint32 w, Uint32 h)
    5.68 +{
    5.69 +    GL_FBOList *result = data->framebuffers;
    5.70 +
    5.71 +    while (result && ((result->w != w) || (result->h != h))) {
    5.72 +        result = result->next;
    5.73 +    }
    5.74 +
    5.75 +    if (!result) {
    5.76 +        result = SDL_malloc(sizeof(GL_FBOList));
    5.77 +        if (result) {
    5.78 +            result->w = w;
    5.79 +            result->h = h;
    5.80 +            data->glGenFramebuffersEXT(1, &result->FBO);
    5.81 +            result->next = data->framebuffers;
    5.82 +            data->framebuffers = result;
    5.83 +        }
    5.84 +    }
    5.85 +    return result;
    5.86 +}
    5.87 +
    5.88  SDL_Renderer *
    5.89  GL_CreateRenderer(SDL_Window * window, Uint32 flags)
    5.90  {
    5.91 @@ -269,6 +315,7 @@
    5.92      renderer->RenderDrawLines = GL_RenderDrawLines;
    5.93      renderer->RenderFillRects = GL_RenderFillRects;
    5.94      renderer->RenderCopy = GL_RenderCopy;
    5.95 +    renderer->SetTargetTexture = GL_SetTargetTexture;
    5.96      renderer->RenderReadPixels = GL_RenderReadPixels;
    5.97      renderer->RenderPresent = GL_RenderPresent;
    5.98      renderer->DestroyTexture = GL_DestroyTexture;
    5.99 @@ -341,6 +388,22 @@
   5.100          renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
   5.101          renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
   5.102      }
   5.103 +    
   5.104 +    if (SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object")) {
   5.105 +        data->GL_EXT_framebuffer_object_supported = SDL_TRUE;
   5.106 +        data->glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
   5.107 +            SDL_GL_GetProcAddress("glGenFramebuffersEXT");
   5.108 +        data->glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
   5.109 +            SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
   5.110 +        data->glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
   5.111 +            SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
   5.112 +        data->glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
   5.113 +            SDL_GL_GetProcAddress("glBindFramebufferEXT");
   5.114 +       data->glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
   5.115 +            SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
   5.116 +    }
   5.117 +    data->framebuffers = NULL;
   5.118 +    data->renderTarget = NULL;
   5.119  
   5.120      /* Set up parameters for rendering */
   5.121      GL_ResetState(renderer);
   5.122 @@ -403,6 +466,74 @@
   5.123  }
   5.124  
   5.125  static int
   5.126 +GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   5.127 +{
   5.128 +    GL_RenderData *data = (GL_RenderData *) renderer->driverdata;    
   5.129 +    
   5.130 +    GL_TextureData *texturedata;
   5.131 +    GLenum status;
   5.132 +
   5.133 +    if (!renderer) return -1;
   5.134 +    GL_ActivateRenderer(renderer);
   5.135 +    
   5.136 +    if (! data->GL_EXT_framebuffer_object_supported) {
   5.137 +        SDL_Unsupported();
   5.138 +        return -1;
   5.139 +    }
   5.140 +    
   5.141 +    if (texture == NULL) {
   5.142 +        if (data->renderTarget != NULL) {
   5.143 +            data->renderTarget = NULL;
   5.144 +            renderer->viewport = data->viewport_copy;
   5.145 +            data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
   5.146 +            data->glMatrixMode(GL_PROJECTION);
   5.147 +            data->glLoadIdentity();
   5.148 +            data->glMatrixMode(GL_MODELVIEW);
   5.149 +            data->glLoadIdentity();
   5.150 +            data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h);
   5.151 +            data->glOrtho(0.0, (GLdouble) renderer->viewport.w, (GLdouble) renderer->viewport.h, 0.0, 0.0, 1.0);
   5.152 +        }
   5.153 +        return 0;
   5.154 +    }
   5.155 +    if (renderer != texture->renderer) return -1;
   5.156 +    if (data->renderTarget==NULL) {
   5.157 +        // Keep a copy of the default viewport to restore when texture==NULL
   5.158 +        data->viewport_copy = renderer->viewport;
   5.159 +    }
   5.160 +    
   5.161 +    
   5.162 +    texturedata = (GL_TextureData *) texture->driverdata;
   5.163 +    if (!texturedata) {
   5.164 +        if (texture->native && texture->native->driverdata) {
   5.165 +            texture = texture->native;
   5.166 +            texturedata = texture->driverdata;
   5.167 +        }
   5.168 +        else return -1;
   5.169 +    }
   5.170 +    data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, texturedata->fbo->FBO);
   5.171 +    /* TODO: check if texture pixel format allows this operation */
   5.172 +    data->glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texturedata->type, texturedata->texture, 0);
   5.173 +    /* Check FBO status */
   5.174 +    status = data->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
   5.175 +    if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
   5.176 +        return -1;
   5.177 +    }
   5.178 +
   5.179 +    data->renderTarget = texture;
   5.180 +    renderer->viewport.x = 0;
   5.181 +    renderer->viewport.y = 0;
   5.182 +    renderer->viewport.w = texture->w;
   5.183 +    renderer->viewport.h = texture->h;
   5.184 +    data->glMatrixMode(GL_PROJECTION);
   5.185 +    data->glLoadIdentity();
   5.186 +    data->glOrtho(0.0, (GLdouble) texture->w, 0.0, (GLdouble) texture->h, 0.0, 1.0);
   5.187 +    data->glMatrixMode(GL_MODELVIEW);
   5.188 +    data->glLoadIdentity();
   5.189 +    data->glViewport(0, 0, texture->w, texture->h);    
   5.190 +    return 0;
   5.191 +}
   5.192 +
   5.193 +static int
   5.194  GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   5.195  {
   5.196      GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
   5.197 @@ -446,10 +577,17 @@
   5.198      }
   5.199  
   5.200      texture->driverdata = data;
   5.201 +    
   5.202 +    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   5.203 +        data->fbo = GL_GetFBO(renderdata, texture->w, texture->h);
   5.204 +    } else {
   5.205 +        data->fbo = NULL;
   5.206 +    }
   5.207  
   5.208      renderdata->glGetError();
   5.209      renderdata->glGenTextures(1, &data->texture);
   5.210 -    if (renderdata->GL_ARB_texture_rectangle_supported) {
   5.211 +    if ((renderdata->GL_ARB_texture_rectangle_supported)
   5.212 +        /*&& texture->access != SDL_TEXTUREACCESS_TARGET*/){
   5.213          data->type = GL_TEXTURE_RECTANGLE_ARB;
   5.214          texture_w = texture->w;
   5.215          texture_h = texture->h;
   5.216 @@ -1013,6 +1151,13 @@
   5.217              GL_DestroyShaderContext(data->shaders);
   5.218          }
   5.219          if (data->context) {
   5.220 +            while (data->framebuffers) {
   5.221 +                GL_FBOList *nextnode = data->framebuffers->next;
   5.222 +                /* delete the framebuffer object */
   5.223 +                data->glDeleteFramebuffersEXT(1, &data->framebuffers->FBO);
   5.224 +                SDL_free(data->framebuffers);
   5.225 +                data->framebuffers = nextnode;
   5.226 +            }            
   5.227              /* SDL_GL_MakeCurrent(0, NULL); *//* doesn't do anything */
   5.228              SDL_GL_DeleteContext(data->context);
   5.229          }
     6.1 --- a/src/render/opengles/SDL_glesfuncs.h	Wed Jan 18 22:22:54 2012 -0500
     6.2 +++ b/src/render/opengles/SDL_glesfuncs.h	Wed Jan 18 22:45:49 2012 -0500
     6.3 @@ -27,5 +27,13 @@
     6.4  SDL_PROC(void, glTexSubImage2D, (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid *))
     6.5  SDL_PROC(void, glVertexPointer, (GLint, GLenum, GLsizei, const GLvoid *))
     6.6  SDL_PROC(void, glViewport, (GLint, GLint, GLsizei, GLsizei))
     6.7 +SDL_PROC(void, glBindFramebufferOES, (GLenum, GLuint))
     6.8 +SDL_PROC(void, glFramebufferTexture2DOES, (GLenum, GLenum, GLenum, GLuint, GLint))
     6.9 +SDL_PROC(GLenum, glCheckFramebufferStatusOES, (GLenum))
    6.10 +SDL_PROC(void, glPushMatrix, (void))
    6.11 +SDL_PROC(void, glTranslatef, (GLfloat, GLfloat, GLfloat))
    6.12 +SDL_PROC(void, glRotatef, (GLfloat, GLfloat, GLfloat, GLfloat))
    6.13 +SDL_PROC(void, glPopMatrix, (void))
    6.14 +SDL_PROC(void, glDeleteFramebuffersOES, (GLsizei, const GLuint*))
    6.15  
    6.16  /* vi: set ts=4 sw=4 expandtab: */
     7.1 --- a/src/render/opengles/SDL_render_gles.c	Wed Jan 18 22:22:54 2012 -0500
     7.2 +++ b/src/render/opengles/SDL_render_gles.c	Wed Jan 18 22:45:49 2012 -0500
     7.3 @@ -73,6 +73,16 @@
     7.4  static void GLES_DestroyTexture(SDL_Renderer * renderer,
     7.5                                  SDL_Texture * texture);
     7.6  static void GLES_DestroyRenderer(SDL_Renderer * renderer);
     7.7 +static int GLES_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
     7.8 +
     7.9 +typedef struct GLES_FBOList GLES_FBOList;
    7.10 +
    7.11 +struct GLES_FBOList
    7.12 +{
    7.13 +   Uint32 w, h;
    7.14 +   GLuint FBO;
    7.15 +   GLES_FBOList *next;
    7.16 +};
    7.17  
    7.18  
    7.19  SDL_RenderDriver GLES_RenderDriver = {
    7.20 @@ -98,6 +108,10 @@
    7.21  #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
    7.22  #include "SDL_glesfuncs.h"
    7.23  #undef SDL_PROC
    7.24 +    SDL_bool GL_OES_framebuffer_object_supported;
    7.25 +    GLES_FBOList *framebuffers;
    7.26 +    SDL_Texture *renderTarget;
    7.27 +    SDL_Rect viewport_copy;
    7.28  
    7.29      SDL_bool useDrawTexture;
    7.30      SDL_bool GL_OES_draw_texture_supported;
    7.31 @@ -113,6 +127,7 @@
    7.32      GLenum formattype;
    7.33      void *pixels;
    7.34      int pitch;
    7.35 +    GLES_FBOList *fbo;
    7.36  } GLES_TextureData;
    7.37  
    7.38  static void
    7.39 @@ -179,6 +194,27 @@
    7.40  
    7.41  static SDL_GLContext SDL_CurrentContext = NULL;
    7.42  
    7.43 +GLES_FBOList *
    7.44 +GLES_GetFBO(GLES_RenderData *data, Uint32 w, Uint32 h)
    7.45 +{
    7.46 +   GLES_FBOList *result = data->framebuffers;
    7.47 +   while ((result) && ((result->w != w) || (result->h != h)) )
    7.48 +   {
    7.49 +       result = result->next;
    7.50 +   }
    7.51 +   if (result == NULL)
    7.52 +   {
    7.53 +       result = SDL_malloc(sizeof(GLES_FBOList));
    7.54 +       result->w = w;
    7.55 +       result->h = h;
    7.56 +       glGenFramebuffersOES(1, &result->FBO);
    7.57 +       result->next = data->framebuffers;
    7.58 +       data->framebuffers = result;
    7.59 +   }
    7.60 +   return result;
    7.61 +}
    7.62 +
    7.63 +
    7.64  static int
    7.65  GLES_ActivateRenderer(SDL_Renderer * renderer)
    7.66  {
    7.67 @@ -221,6 +257,71 @@
    7.68      data->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    7.69  }
    7.70  
    7.71 +static int
    7.72 +GLES_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
    7.73 +{
    7.74 +    GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
    7.75 +    int w, h;
    7.76 +    GLES_TextureData *texturedata = NULL;
    7.77 +    GLenum status;
    7.78 +
    7.79 +    if (!renderer) return -1;
    7.80 +    GLES_ActivateRenderer(renderer);
    7.81 +    if (! data->GL_OES_framebuffer_object_supported) {
    7.82 +        SDL_Unsupported();
    7.83 +        return -1;
    7.84 +    }
    7.85 +
    7.86 +    if (texture == NULL) {
    7.87 +        if (data->renderTarget != NULL) {
    7.88 +            data->renderTarget = NULL;
    7.89 +            renderer->viewport = data->viewport_copy;
    7.90 +            data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
    7.91 +            data->glMatrixMode(GL_PROJECTION);
    7.92 +            data->glLoadIdentity();
    7.93 +            data->glMatrixMode(GL_MODELVIEW);
    7.94 +            data->glLoadIdentity();
    7.95 +            data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h);
    7.96 +            data->glOrthof(0.0, (GLfloat) renderer->viewport.w, (GLfloat) renderer->viewport.h, 0.0, 0.0, 1.0);
    7.97 +        }
    7.98 +        return 0;
    7.99 +    }
   7.100 +
   7.101 +    if (renderer != texture->renderer) return -1;
   7.102 +    if (data->renderTarget==NULL) {
   7.103 +        // Keep a copy of the default viewport to restore when texture==NULL
   7.104 +        data->viewport_copy = renderer->viewport;
   7.105 +    }
   7.106 +    texturedata = (GLES_TextureData *) texture->driverdata;
   7.107 +    if (!texturedata) {
   7.108 +        if (texture->native && texture->native->driverdata) {
   7.109 +            texture = texture->native;
   7.110 +            texturedata = texture->driverdata;
   7.111 +        }
   7.112 +        else return -1;
   7.113 +    }
   7.114 +    data->glBindFramebufferOES(GL_FRAMEBUFFER_OES, texturedata->fbo->FBO);
   7.115 +    /* TODO: check if texture pixel format allows this operation */
   7.116 +    data->glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, texturedata->type, texturedata->texture, 0);
   7.117 +    /* Check FBO status */
   7.118 +    status = data->glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
   7.119 +    if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
   7.120 +        return -1;
   7.121 +    }
   7.122 +    data->renderTarget = texture;
   7.123 +    renderer->viewport.x = 0;
   7.124 +    renderer->viewport.y = 0;
   7.125 +    renderer->viewport.w = texture->w;
   7.126 +    renderer->viewport.h = texture->h;
   7.127 +    data->glMatrixMode(GL_PROJECTION);
   7.128 +    data->glLoadIdentity();
   7.129 +    data->glOrthof(0.0, (GLfloat) texture->w, 0.0, (GLfloat) texture->h, 0.0, 1.0);
   7.130 +    data->glMatrixMode(GL_MODELVIEW);
   7.131 +    data->glLoadIdentity();
   7.132 +    data->glViewport(0, 0, texture->w, texture->h);
   7.133 +    return 0;
   7.134 +}
   7.135 +
   7.136  SDL_Renderer *
   7.137  GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
   7.138  {
   7.139 @@ -274,6 +375,7 @@
   7.140      renderer->info.flags = SDL_RENDERER_ACCELERATED;
   7.141      renderer->driverdata = data;
   7.142      renderer->window = window;
   7.143 +    renderer->SetTargetTexture = GLES_SetTargetTexture;
   7.144  
   7.145      data->context = SDL_GL_CreateContext(window);
   7.146      if (!data->context) {
   7.147 @@ -317,6 +419,12 @@
   7.148      data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
   7.149      renderer->info.max_texture_height = value;
   7.150  
   7.151 +    if (SDL_GL_ExtensionSupported("GL_OES_framebuffer_object")) {
   7.152 +        data->GL_OES_framebuffer_object_supported = SDL_TRUE;
   7.153 +    }
   7.154 +    data->framebuffers = NULL;
   7.155 +    data->renderTarget = NULL;
   7.156 +
   7.157      /* Set up parameters for rendering */
   7.158      GLES_ResetState(renderer);
   7.159  
   7.160 @@ -335,7 +443,7 @@
   7.161  
   7.162      if (event->event == SDL_WINDOWEVENT_MINIMIZED) {
   7.163          /* According to Apple documentation, we need to finish drawing NOW! */
   7.164 -	data->glFinish();
   7.165 +        data->glFinish();
   7.166      }
   7.167  }
   7.168  
   7.169 @@ -403,6 +511,11 @@
   7.170      }
   7.171  
   7.172      texture->driverdata = data;
   7.173 +    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   7.174 +       data->fbo = GLES_GetFBO(renderer->driverdata, texture->w, texture->h);
   7.175 +    } else {
   7.176 +       data->fbo = NULL;
   7.177 +    }
   7.178  
   7.179      renderdata->glGetError();
   7.180      renderdata->glEnable(GL_TEXTURE_2D);
   7.181 @@ -757,15 +870,26 @@
   7.182          SDL_Window *window = renderer->window;
   7.183  
   7.184          SDL_GetWindowSize(window, &w, &h);
   7.185 -        cropRect[0] = srcrect->x;
   7.186 -        cropRect[1] = srcrect->y + srcrect->h;
   7.187 -        cropRect[2] = srcrect->w;
   7.188 -        cropRect[3] = -srcrect->h;
   7.189 -        data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   7.190 -                               cropRect);
   7.191 -        data->glDrawTexiOES(renderer->viewport.x + dstrect->x,
   7.192 -	              h - (renderer->viewport.y + dstrect->y) - dstrect->h, 0,
   7.193 -                            dstrect->w, dstrect->h);
   7.194 +        if (data->renderTarget != NULL) {
   7.195 +            cropRect[0] = srcrect->x;
   7.196 +            cropRect[1] = srcrect->y;
   7.197 +            cropRect[2] = srcrect->w;
   7.198 +            cropRect[3] = srcrect->h;
   7.199 +            data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   7.200 +                                   cropRect);
   7.201 +            data->glDrawTexiOES(renderer->viewport.x + dstrect->x, renderer->viewport.y + dstrect->y, 0,
   7.202 +                                dstrect->w, dstrect->h);
   7.203 +        } else {
   7.204 +            cropRect[0] = srcrect->x;
   7.205 +            cropRect[1] = srcrect->y + srcrect->h;
   7.206 +            cropRect[2] = srcrect->w;
   7.207 +            cropRect[3] = -srcrect->h;
   7.208 +            data->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES,
   7.209 +                                   cropRect);
   7.210 +            data->glDrawTexiOES(renderer->viewport.x + dstrect->x,
   7.211 +                        h - (renderer->viewport.y + dstrect->y) - dstrect->h, 0,
   7.212 +                        dstrect->w, dstrect->h);
   7.213 +        }
   7.214      } else {
   7.215  
   7.216          minx = dstrect->x;
   7.217 @@ -901,6 +1025,12 @@
   7.218  
   7.219      if (data) {
   7.220          if (data->context) {
   7.221 +            while (data->framebuffers) {
   7.222 +               GLES_FBOList *nextnode = data->framebuffers->next;
   7.223 +               data->glDeleteFramebuffersOES(1, &data->framebuffers->FBO);
   7.224 +               SDL_free(data->framebuffers);
   7.225 +               data->framebuffers = nextnode;
   7.226 +            }
   7.227              SDL_GL_DeleteContext(data->context);
   7.228          }
   7.229          SDL_free(data);
     8.1 --- a/src/render/opengles2/SDL_gles2funcs.h	Wed Jan 18 22:22:54 2012 -0500
     8.2 +++ b/src/render/opengles2/SDL_gles2funcs.h	Wed Jan 18 22:45:49 2012 -0500
     8.3 @@ -40,3 +40,7 @@
     8.4  SDL_PROC(void, glUseProgram, (GLuint))
     8.5  SDL_PROC(void, glVertexAttribPointer, (GLuint, GLint, GLenum, GLboolean, GLsizei, const void *))
     8.6  SDL_PROC(void, glViewport, (GLint, GLint, GLsizei, GLsizei))
     8.7 +SDL_PROC(void, glBindFramebuffer, (GLenum, GLuint))
     8.8 +SDL_PROC(void, glFramebufferTexture2D, (GLenum, GLenum, GLenum, GLuint, GLint))
     8.9 +SDL_PROC(GLenum, glCheckFramebufferStatus, (GLenum))
    8.10 +SDL_PROC(void, glDeleteFramebuffers, (GLsizei, const GLuint *))
     9.1 --- a/src/render/opengles2/SDL_render_gles2.c	Wed Jan 18 22:22:54 2012 -0500
     9.2 +++ b/src/render/opengles2/SDL_render_gles2.c	Wed Jan 18 22:45:49 2012 -0500
     9.3 @@ -55,6 +55,15 @@
     9.4   * Context structures                                                                            *
     9.5   *************************************************************************************************/
     9.6  
     9.7 +typedef struct GLES2_FBOList GLES2_FBOList;
     9.8 +
     9.9 +struct GLES2_FBOList
    9.10 +{
    9.11 +   Uint32 w, h;
    9.12 +   GLuint FBO;
    9.13 +   GLES2_FBOList *next;
    9.14 +};
    9.15 +
    9.16  typedef struct GLES2_TextureData
    9.17  {
    9.18      GLenum texture;
    9.19 @@ -63,6 +72,7 @@
    9.20      GLenum pixel_type;
    9.21      void *pixel_data;
    9.22      size_t pitch;
    9.23 +    GLES2_FBOList *fbo;
    9.24  } GLES2_TextureData;
    9.25  
    9.26  typedef struct GLES2_ShaderCacheEntry
    9.27 @@ -134,6 +144,9 @@
    9.28  #define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
    9.29  #include "SDL_gles2funcs.h"
    9.30  #undef SDL_PROC
    9.31 +    GLES2_FBOList *framebuffers;
    9.32 +    SDL_Texture *renderTarget;
    9.33 +    SDL_Rect viewport_copy;
    9.34  
    9.35      int shader_format_count;
    9.36      GLenum *shader_formats;
    9.37 @@ -154,6 +167,8 @@
    9.38  static int GLES2_UpdateViewport(SDL_Renderer * renderer);
    9.39  static void GLES2_DestroyRenderer(SDL_Renderer *renderer);
    9.40  
    9.41 +static int GLES2_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    9.42 +
    9.43  static SDL_GLContext SDL_CurrentContext = NULL;
    9.44  
    9.45  static int GLES2_LoadFunctions(GLES2_DriverContext * data)
    9.46 @@ -176,7 +191,7 @@
    9.47              SDL_SetError("Couldn't load GLES2 function %s: %s\n", #func, SDL_GetError()); \
    9.48              return -1; \
    9.49          } \
    9.50 -    } while ( 0 );  
    9.51 +    } while ( 0 );
    9.52  #endif /* _SDL_NOGETPROCADDR_ */
    9.53  
    9.54  #include "SDL_gles2funcs.h"
    9.55 @@ -184,6 +199,26 @@
    9.56      return 0;
    9.57  }
    9.58  
    9.59 +GLES2_FBOList *
    9.60 +GLES2_GetFBO(GLES2_DriverContext *data, Uint32 w, Uint32 h)
    9.61 +{
    9.62 +   GLES2_FBOList *result = data->framebuffers;
    9.63 +   while ((result) && ((result->w != w) || (result->h != h)) )
    9.64 +   {
    9.65 +       result = result->next;
    9.66 +   }
    9.67 +   if (result == NULL)
    9.68 +   {
    9.69 +       result = SDL_malloc(sizeof(GLES2_FBOList));
    9.70 +       result->w = w;
    9.71 +       result->h = h;
    9.72 +       glGenFramebuffers(1, &result->FBO);
    9.73 +       result->next = data->framebuffers;
    9.74 +       data->framebuffers = result;
    9.75 +   }
    9.76 +   return result;
    9.77 +}
    9.78 +
    9.79  static int
    9.80  GLES2_ActivateRenderer(SDL_Renderer * renderer)
    9.81  {
    9.82 @@ -207,7 +242,7 @@
    9.83  GLES2_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
    9.84  {
    9.85      GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
    9.86 -    
    9.87 +
    9.88      if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
    9.89          /* Rebind the context to the window area */
    9.90          SDL_CurrentContext = NULL;
    9.91 @@ -267,6 +302,12 @@
    9.92              }
    9.93          }
    9.94          if (rdata->context) {
    9.95 +            while (rdata->framebuffers) {
    9.96 +                GLES2_FBOList *nextnode = rdata->framebuffers->next;
    9.97 +                rdata->glDeleteFramebuffers(1, &rdata->framebuffers->FBO);
    9.98 +                SDL_free(rdata->framebuffers);
    9.99 +                rdata->framebuffers = nextnode;
   9.100 +            }
   9.101              SDL_GL_DeleteContext(rdata->context);
   9.102          }
   9.103          if (rdata->shader_formats) {
   9.104 @@ -371,6 +412,13 @@
   9.105          return -1;
   9.106      }
   9.107      texture->driverdata = tdata;
   9.108 +
   9.109 +    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
   9.110 +       tdata->fbo = GLES2_GetFBO(renderer->driverdata, texture->w, texture->h);
   9.111 +    } else {
   9.112 +       tdata->fbo = NULL;
   9.113 +    }
   9.114 +
   9.115      return 0;
   9.116  }
   9.117  
   9.118 @@ -433,7 +481,7 @@
   9.119      int y;
   9.120  
   9.121      GLES2_ActivateRenderer(renderer);
   9.122 -    
   9.123 +
   9.124      /* Bail out if we're supposed to update an empty rectangle */
   9.125      if (rect->w <= 0 || rect->h <= 0)
   9.126          return 0;
   9.127 @@ -543,7 +591,7 @@
   9.128      entry->vertex_shader = vertex;
   9.129      entry->fragment_shader = fragment;
   9.130      entry->blend_mode = blendMode;
   9.131 -    
   9.132 +
   9.133      /* Create the program and link it */
   9.134      rdata->glGetError();
   9.135      entry->id = rdata->glCreateProgram();
   9.136 @@ -560,7 +608,7 @@
   9.137          SDL_free(entry);
   9.138          return NULL;
   9.139      }
   9.140 -    
   9.141 +
   9.142      /* Predetermine locations of uniform variables */
   9.143      entry->uniform_locations[GLES2_UNIFORM_PROJECTION] =
   9.144          rdata->glGetUniformLocation(entry->id, "u_projection");
   9.145 @@ -625,7 +673,7 @@
   9.146          SDL_SetError("No shader matching the requested characteristics was found");
   9.147          return NULL;
   9.148      }
   9.149 -    
   9.150 +
   9.151      /* Find a matching shader instance that's supported on this hardware */
   9.152      for (i = 0; i < shader->instance_count && !instance; ++i)
   9.153      {
   9.154 @@ -872,7 +920,7 @@
   9.155      GLES2_DriverContext *rdata = (GLES2_DriverContext *)renderer->driverdata;
   9.156  
   9.157      GLES2_ActivateRenderer(renderer);
   9.158 -    
   9.159 +
   9.160      rdata->glClearColor((GLfloat) renderer->r * inv255f,
   9.161                   (GLfloat) renderer->g * inv255f,
   9.162                   (GLfloat) renderer->b * inv255f,
   9.163 @@ -1080,20 +1128,83 @@
   9.164  
   9.165      /* Activate an appropriate shader and set the projection matrix */
   9.166      blendMode = texture->blendMode;
   9.167 -    switch (texture->format)
   9.168 -    {
   9.169 -        case SDL_PIXELFORMAT_ABGR8888:
   9.170 -            sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   9.171 -            break;
   9.172 -        case SDL_PIXELFORMAT_ARGB8888:
   9.173 -            sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   9.174 -            break;
   9.175 -        case SDL_PIXELFORMAT_BGR888:
   9.176 -            sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   9.177 -            break;
   9.178 -        case SDL_PIXELFORMAT_RGB888:
   9.179 -            sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
   9.180 -            break;
   9.181 +    if (rdata->renderTarget!=NULL) {
   9.182 +        /* Check if we need to do color mapping between the source and render target textures */
   9.183 +        if (rdata->renderTarget->format != texture->format) {
   9.184 +            switch (texture->format)
   9.185 +            {
   9.186 +            case SDL_PIXELFORMAT_ABGR8888:
   9.187 +                switch (rdata->renderTarget->format)
   9.188 +                {
   9.189 +                    case SDL_PIXELFORMAT_ARGB8888:
   9.190 +                    case SDL_PIXELFORMAT_RGB888:
   9.191 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   9.192 +                        break;
   9.193 +                    case SDL_PIXELFORMAT_BGR888:
   9.194 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   9.195 +                        break;
   9.196 +                }
   9.197 +                break;
   9.198 +            case SDL_PIXELFORMAT_ARGB8888:
   9.199 +                switch (rdata->renderTarget->format)
   9.200 +                {
   9.201 +                    case SDL_PIXELFORMAT_ABGR8888:
   9.202 +                    case SDL_PIXELFORMAT_BGR888:
   9.203 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   9.204 +                        break;
   9.205 +                    case SDL_PIXELFORMAT_RGB888:
   9.206 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   9.207 +                        break;
   9.208 +                }
   9.209 +                break;
   9.210 +            case SDL_PIXELFORMAT_BGR888:
   9.211 +                switch (rdata->renderTarget->format)
   9.212 +                {
   9.213 +                    case SDL_PIXELFORMAT_ABGR8888:
   9.214 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   9.215 +                        break;
   9.216 +                    case SDL_PIXELFORMAT_ARGB8888:
   9.217 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
   9.218 +                        break;
   9.219 +                    case SDL_PIXELFORMAT_RGB888:
   9.220 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   9.221 +                        break;
   9.222 +                }
   9.223 +                break;
   9.224 +            case SDL_PIXELFORMAT_RGB888:
   9.225 +                switch (rdata->renderTarget->format)
   9.226 +                {
   9.227 +                    case SDL_PIXELFORMAT_ABGR8888:
   9.228 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   9.229 +                        break;
   9.230 +                    case SDL_PIXELFORMAT_ARGB8888:
   9.231 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   9.232 +                        break;
   9.233 +                    case SDL_PIXELFORMAT_BGR888:
   9.234 +                        sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   9.235 +                        break;
   9.236 +                }
   9.237 +                break;
   9.238 +            }
   9.239 +        }
   9.240 +        else sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;   // Texture formats match, use the non color mapping shader (even if the formats are not ABGR)
   9.241 +    }
   9.242 +    else {
   9.243 +        switch (texture->format)
   9.244 +        {
   9.245 +            case SDL_PIXELFORMAT_ABGR8888:
   9.246 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
   9.247 +                break;
   9.248 +            case SDL_PIXELFORMAT_ARGB8888:
   9.249 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_ARGB;
   9.250 +                break;
   9.251 +            case SDL_PIXELFORMAT_BGR888:
   9.252 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_BGR;
   9.253 +                break;
   9.254 +            case SDL_PIXELFORMAT_RGB888:
   9.255 +                sourceType = GLES2_IMAGESOURCE_TEXTURE_RGB;
   9.256 +                break;
   9.257 +        }
   9.258      }
   9.259      if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0)
   9.260          return -1;
   9.261 @@ -1119,15 +1230,29 @@
   9.262      GLES2_SetTexCoords(rdata, SDL_TRUE);
   9.263  
   9.264      /* Emit the textured quad */
   9.265 -    vertices[0] = (GLfloat)dstrect->x;
   9.266 -    vertices[1] = (GLfloat)dstrect->y;
   9.267 -    vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
   9.268 -    vertices[3] = (GLfloat)dstrect->y;
   9.269 -    vertices[4] = (GLfloat)dstrect->x;
   9.270 -    vertices[5] = (GLfloat)(dstrect->y + dstrect->h);
   9.271 -    vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
   9.272 -    vertices[7] = (GLfloat)(dstrect->y + dstrect->h);
   9.273 +    if (rdata->renderTarget!=NULL) {
   9.274 +        // Flip the texture vertically to compensate for the inversion it'll be subjected to later when it's rendered to the screen
   9.275 +        vertices[0] = (GLfloat)dstrect->x;
   9.276 +        vertices[1] = (GLfloat)renderer->viewport.h-dstrect->y;
   9.277 +        vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
   9.278 +        vertices[3] = (GLfloat)renderer->viewport.h-dstrect->y;
   9.279 +        vertices[4] = (GLfloat)dstrect->x;
   9.280 +        vertices[5] = (GLfloat)renderer->viewport.h-(dstrect->y + dstrect->h);
   9.281 +        vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
   9.282 +        vertices[7] = (GLfloat)renderer->viewport.h-(dstrect->y + dstrect->h);
   9.283 +    }
   9.284 +    else {
   9.285 +        vertices[0] = (GLfloat)dstrect->x;
   9.286 +        vertices[1] = (GLfloat)dstrect->y;
   9.287 +        vertices[2] = (GLfloat)(dstrect->x + dstrect->w);
   9.288 +        vertices[3] = (GLfloat)dstrect->y;
   9.289 +        vertices[4] = (GLfloat)dstrect->x;
   9.290 +        vertices[5] = (GLfloat)(dstrect->y + dstrect->h);
   9.291 +        vertices[6] = (GLfloat)(dstrect->x + dstrect->w);
   9.292 +        vertices[7] = (GLfloat)(dstrect->y + dstrect->h);
   9.293 +    }
   9.294      rdata->glVertexAttribPointer(GLES2_ATTRIBUTE_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
   9.295 +
   9.296      texCoords[0] = srcrect->x / (GLfloat)texture->w;
   9.297      texCoords[1] = srcrect->y / (GLfloat)texture->h;
   9.298      texCoords[2] = (srcrect->x + srcrect->w) / (GLfloat)texture->w;
   9.299 @@ -1231,6 +1356,60 @@
   9.300      rdata->glDisableVertexAttribArray(GLES2_ATTRIBUTE_TEXCOORD);
   9.301  }
   9.302  
   9.303 +static int
   9.304 +GLES2_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   9.305 +{
   9.306 +    GLES2_DriverContext *data = (GLES2_DriverContext *) renderer->driverdata;
   9.307 +    GLES2_TextureData *texturedata = NULL;
   9.308 +    GLenum status;
   9.309 +    SDL_BlendMode blendMode;
   9.310 +
   9.311 +    if (!renderer) return -1;
   9.312 +
   9.313 +    blendMode = texture->blendMode;
   9.314 +    if (texture == NULL) {
   9.315 +        if (data->renderTarget!=NULL) {
   9.316 +            data->glBindFramebuffer(GL_FRAMEBUFFER, 0);
   9.317 +            renderer->viewport = data->viewport_copy;
   9.318 +            data->renderTarget = NULL;
   9.319 +            data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h);
   9.320 +            if(data->current_program) GLES2_SetOrthographicProjection(renderer);
   9.321 +        }
   9.322 +        return 0;
   9.323 +    }
   9.324 +    if (renderer != texture->renderer) return -1;
   9.325 +    if (data->renderTarget==NULL) {
   9.326 +        // Keep a copy of the default viewport to restore when texture==NULL
   9.327 +        data->viewport_copy = renderer->viewport;
   9.328 +    }
   9.329 +
   9.330 +    texturedata = (GLES2_TextureData *) texture->driverdata;
   9.331 +    if (!texturedata) {
   9.332 +        if (texture->native && texture->native->driverdata) {
   9.333 +            texture = texture->native;
   9.334 +            texturedata = texture->driverdata;
   9.335 +        }
   9.336 +        else return -1;
   9.337 +    }
   9.338 +    data->glBindFramebuffer(GL_FRAMEBUFFER, texturedata->fbo->FBO);
   9.339 +    /* TODO: check if texture pixel format allows this operation */
   9.340 +    data->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texturedata->texture_type, texturedata->texture, 0);
   9.341 +    /* Check FBO status */
   9.342 +    status = data->glCheckFramebufferStatus(GL_FRAMEBUFFER);
   9.343 +    if (status != GL_FRAMEBUFFER_COMPLETE) {
   9.344 +        return -1;
   9.345 +    }
   9.346 +    
   9.347 +    renderer->viewport.x = 0;
   9.348 +    renderer->viewport.y = 0;
   9.349 +    renderer->viewport.w = texture->w;
   9.350 +    renderer->viewport.h = texture->h;
   9.351 +    data->renderTarget = texture;
   9.352 +    data->glViewport(0, 0, texture->w, texture->h);
   9.353 +    if(data->current_program) GLES2_SetOrthographicProjection(renderer);
   9.354 +    return 0;
   9.355 +}
   9.356 +
   9.357  static SDL_Renderer *
   9.358  GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
   9.359  {
   9.360 @@ -1241,10 +1420,10 @@
   9.361      GLboolean hasCompiler;
   9.362  #endif
   9.363      Uint32 windowFlags;
   9.364 -    
   9.365 +
   9.366      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
   9.367      SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
   9.368 -    
   9.369 +
   9.370      windowFlags = SDL_GetWindowFlags(window);
   9.371      if (!(windowFlags & SDL_WINDOW_OPENGL)) {
   9.372          if (SDL_RecreateWindow(window, windowFlags | SDL_WINDOW_OPENGL) < 0) {
   9.373 @@ -1331,6 +1510,9 @@
   9.374          rdata->shader_formats[nFormats - 1] = (GLenum)-1;
   9.375  #endif /* ZUNE_HD */
   9.376  
   9.377 +    rdata->framebuffers = NULL;
   9.378 +    rdata->renderTarget = NULL;
   9.379 +
   9.380      /* Populate the function pointers for the module */
   9.381      renderer->WindowEvent         = &GLES2_WindowEvent;
   9.382      renderer->CreateTexture       = &GLES2_CreateTexture;
   9.383 @@ -1347,6 +1529,7 @@
   9.384      renderer->RenderPresent       = &GLES2_RenderPresent;
   9.385      renderer->DestroyTexture      = &GLES2_DestroyTexture;
   9.386      renderer->DestroyRenderer     = &GLES2_DestroyRenderer;
   9.387 +    renderer->SetTargetTexture    = &GLES2_SetTargetTexture;
   9.388  
   9.389      GLES2_ResetState(renderer);
   9.390  
    10.1 --- a/test/Makefile.in	Wed Jan 18 22:22:54 2012 -0500
    10.2 +++ b/test/Makefile.in	Wed Jan 18 22:45:49 2012 -0500
    10.3 @@ -44,6 +44,7 @@
    10.4  	testoverlay2$(EXE) \
    10.5  	testplatform$(EXE) \
    10.6  	testpower$(EXE) \
    10.7 +	testrendertarget$(EXE) \
    10.8  	testresample$(EXE) \
    10.9  	testscale$(EXE) \
   10.10  	testsem$(EXE) \
   10.11 @@ -181,6 +182,9 @@
   10.12  testpower$(EXE): $(srcdir)/testpower.c
   10.13  	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
   10.14  
   10.15 +testrendertarget$(EXE): $(srcdir)/testrendertarget.c $(srcdir)/common.c
   10.16 +	$(CC) -o $@ $(srcdir)/testrendertarget.c $(srcdir)/common.c $(CFLAGS) $(LIBS)
   10.17 +
   10.18  testscale$(EXE): $(srcdir)/testscale.c $(srcdir)/common.c
   10.19  	$(CC) -o $@ $(srcdir)/testscale.c $(srcdir)/common.c $(CFLAGS) $(LIBS)
   10.20  
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/test/testrendertarget.c	Wed Jan 18 22:45:49 2012 -0500
    11.3 @@ -0,0 +1,204 @@
    11.4 +/*
    11.5 +  Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
    11.6 +
    11.7 +  This software is provided 'as-is', without any express or implied
    11.8 +  warranty.  In no event will the authors be held liable for any damages
    11.9 +  arising from the use of this software.
   11.10 +
   11.11 +  Permission is granted to anyone to use this software for any purpose,
   11.12 +  including commercial applications, and to alter it and redistribute it
   11.13 +  freely.
   11.14 +*/
   11.15 +/* Simple program:  Move N sprites around on the screen as fast as possible */
   11.16 +
   11.17 +#include <stdlib.h>
   11.18 +#include <stdio.h>
   11.19 +#include <time.h>
   11.20 +
   11.21 +#include "SDL.h"
   11.22 +#include "common.h"
   11.23 +
   11.24 +#define WINDOW_WIDTH    640
   11.25 +#define WINDOW_HEIGHT   480
   11.26 +
   11.27 +static CommonState *state;
   11.28 +
   11.29 +typedef struct {
   11.30 +    SDL_Window *window;
   11.31 +    SDL_Renderer *renderer;
   11.32 +    SDL_Texture *background;
   11.33 +    SDL_Texture *sprite;
   11.34 +    SDL_Rect sprite_rect;
   11.35 +    int scale_direction;
   11.36 +} DrawState;
   11.37 +
   11.38 +/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
   11.39 +static void
   11.40 +quit(int rc)
   11.41 +{
   11.42 +    CommonQuit(state);
   11.43 +    exit(rc);
   11.44 +}
   11.45 +
   11.46 +SDL_Texture *
   11.47 +LoadTexture(SDL_Renderer *renderer, char *file, SDL_bool transparent)
   11.48 +{
   11.49 +    SDL_Surface *temp;
   11.50 +    SDL_Texture *texture;
   11.51 +
   11.52 +    /* Load the sprite image */
   11.53 +    temp = SDL_LoadBMP(file);
   11.54 +    if (temp == NULL) {
   11.55 +        fprintf(stderr, "Couldn't load %s: %s", file, SDL_GetError());
   11.56 +        return NULL;
   11.57 +    }
   11.58 +
   11.59 +    /* Set transparent pixel as the pixel at (0,0) */
   11.60 +    if (transparent) {
   11.61 +        if (temp->format->palette) {
   11.62 +            SDL_SetColorKey(temp, SDL_TRUE, *(Uint8 *) temp->pixels);
   11.63 +        } else {
   11.64 +            switch (temp->format->BitsPerPixel) {
   11.65 +            case 15:
   11.66 +                SDL_SetColorKey(temp, SDL_TRUE,
   11.67 +                                (*(Uint16 *) temp->pixels) & 0x00007FFF);
   11.68 +                break;
   11.69 +            case 16:
   11.70 +                SDL_SetColorKey(temp, SDL_TRUE, *(Uint16 *) temp->pixels);
   11.71 +                break;
   11.72 +            case 24:
   11.73 +                SDL_SetColorKey(temp, SDL_TRUE,
   11.74 +                                (*(Uint32 *) temp->pixels) & 0x00FFFFFF);
   11.75 +                break;
   11.76 +            case 32:
   11.77 +                SDL_SetColorKey(temp, SDL_TRUE, *(Uint32 *) temp->pixels);
   11.78 +                break;
   11.79 +            }
   11.80 +        }
   11.81 +    }
   11.82 +
   11.83 +    /* Create textures from the image */
   11.84 +    texture = SDL_CreateTextureFromSurface(renderer, temp);
   11.85 +    if (!texture) {
   11.86 +        fprintf(stderr, "Couldn't create texture: %s\n", SDL_GetError());
   11.87 +        SDL_FreeSurface(temp);
   11.88 +        return NULL;
   11.89 +    }
   11.90 +    SDL_FreeSurface(temp);
   11.91 +
   11.92 +    /* We're ready to roll. :) */
   11.93 +    return texture;
   11.94 +}
   11.95 +
   11.96 +void
   11.97 +Draw(DrawState *s)
   11.98 +{
   11.99 +    SDL_Rect viewport;
  11.100 +    SDL_Texture *target;
  11.101 +
  11.102 +    SDL_RenderGetViewport(s->renderer, &viewport);
  11.103 +
  11.104 +    target = SDL_CreateTexture(s->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, viewport.w, viewport.h);
  11.105 +    SDL_SetTargetTexture(s->renderer, target);
  11.106 +
  11.107 +    /* Draw the background */
  11.108 +    SDL_RenderCopy(s->renderer, s->background, NULL, NULL);
  11.109 +
  11.110 +    /* Scale and draw the sprite */
  11.111 +    s->sprite_rect.w += s->scale_direction;
  11.112 +    s->sprite_rect.h += s->scale_direction;
  11.113 +    if (s->scale_direction > 0) {
  11.114 +        if (s->sprite_rect.w >= viewport.w || s->sprite_rect.h >= viewport.h) {
  11.115 +            s->scale_direction = -1;
  11.116 +        }
  11.117 +    } else {
  11.118 +        if (s->sprite_rect.w <= 1 || s->sprite_rect.h <= 1) {
  11.119 +            s->scale_direction = 1;
  11.120 +        }
  11.121 +    }
  11.122 +    s->sprite_rect.x = (viewport.w - s->sprite_rect.w) / 2;
  11.123 +    s->sprite_rect.y = (viewport.h - s->sprite_rect.h) / 2;
  11.124 +
  11.125 +    SDL_RenderCopy(s->renderer, s->sprite, NULL, &s->sprite_rect);
  11.126 +
  11.127 +    SDL_SetTargetTexture(s->renderer, NULL);
  11.128 +    SDL_RenderCopy(s->renderer, target, NULL, NULL);
  11.129 +    SDL_DestroyTexture(target);
  11.130 +
  11.131 +    /* Update the screen! */
  11.132 +    SDL_RenderPresent(s->renderer);
  11.133 +}
  11.134 +
  11.135 +int
  11.136 +main(int argc, char *argv[])
  11.137 +{
  11.138 +    DrawState *drawstates;
  11.139 +    int i, done;
  11.140 +    SDL_Event event;
  11.141 +    int frames;
  11.142 +    Uint32 then, now;
  11.143 +
  11.144 +    /* Initialize test framework */
  11.145 +    state = CommonCreateState(argv, SDL_INIT_VIDEO);
  11.146 +    if (!state) {
  11.147 +        return 1;
  11.148 +    }
  11.149 +    for (i = 1; i < argc;) {
  11.150 +        int consumed;
  11.151 +
  11.152 +        consumed = CommonArg(state, i);
  11.153 +        if (consumed == 0) {
  11.154 +            fprintf(stderr, "Usage: %s %s\n", argv[0], CommonUsage(state));
  11.155 +            return 1;
  11.156 +        }
  11.157 +        i += consumed;
  11.158 +    }
  11.159 +    if (!CommonInit(state)) {
  11.160 +        quit(2);
  11.161 +    }
  11.162 +
  11.163 +    drawstates = SDL_stack_alloc(DrawState, state->num_windows);
  11.164 +    for (i = 0; i < state->num_windows; ++i) {
  11.165 +        DrawState *drawstate = &drawstates[i];
  11.166 +
  11.167 +        drawstate->window = state->windows[i];
  11.168 +        drawstate->renderer = state->renderers[i];
  11.169 +        drawstate->sprite = LoadTexture(drawstate->renderer, "icon.bmp", SDL_TRUE);
  11.170 +        drawstate->background = LoadTexture(drawstate->renderer, "sample.bmp", SDL_FALSE);
  11.171 +        if (!drawstate->sprite || !drawstate->background) {
  11.172 +            quit(2);
  11.173 +        }
  11.174 +        SDL_QueryTexture(drawstate->sprite, NULL, NULL,
  11.175 +                         &drawstate->sprite_rect.w, &drawstate->sprite_rect.h);
  11.176 +        drawstate->scale_direction = 1;
  11.177 +    }
  11.178 +
  11.179 +    /* Main render loop */
  11.180 +    frames = 0;
  11.181 +    then = SDL_GetTicks();
  11.182 +    done = 0;
  11.183 +    while (!done) {
  11.184 +        /* Check for events */
  11.185 +        ++frames;
  11.186 +        while (SDL_PollEvent(&event)) {
  11.187 +            CommonEvent(state, &event, &done);
  11.188 +        }
  11.189 +        for (i = 0; i < state->num_windows; ++i) {
  11.190 +            Draw(&drawstates[i]);
  11.191 +        }
  11.192 +    }
  11.193 +
  11.194 +    /* Print out some timing information */
  11.195 +    now = SDL_GetTicks();
  11.196 +    if (now > then) {
  11.197 +        double fps = ((double) frames * 1000) / (now - then);
  11.198 +        printf("%2.2f frames per second\n", fps);
  11.199 +    }
  11.200 +
  11.201 +    SDL_stack_free(drawstates);
  11.202 +
  11.203 +    quit(0);
  11.204 +    return 0;
  11.205 +}
  11.206 +
  11.207 +/* vi: set ts=4 sw=4 expandtab: */