Implementation of render targets, by Mason Wheeler and Gabriel Jacobo
Thanks guys!
This commit is contained in:
parent
2e70e7f3cb
commit
a49a88676f
11 changed files with 879 additions and 45 deletions
|
@ -66,6 +66,7 @@ static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
|
|||
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 @@ SDL_RenderDriver GL_RenderDriver = {
|
|||
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,11 @@ typedef struct
|
|||
Uint32 color;
|
||||
int blendMode;
|
||||
} current;
|
||||
|
||||
SDL_bool GL_EXT_framebuffer_object_supported;
|
||||
GL_FBOList *framebuffers;
|
||||
SDL_Texture *renderTarget;
|
||||
SDL_Rect viewport_copy;
|
||||
|
||||
/* OpenGL functions */
|
||||
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
|
||||
|
@ -101,6 +116,12 @@ typedef struct
|
|||
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 +144,8 @@ typedef struct
|
|||
SDL_bool yuv;
|
||||
GLuint utexture;
|
||||
GLuint vtexture;
|
||||
|
||||
GL_FBOList *fbo;
|
||||
} GL_TextureData;
|
||||
|
||||
|
||||
|
@ -227,6 +250,29 @@ GL_ResetState(SDL_Renderer *renderer)
|
|||
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) {
|
||||
result = SDL_malloc(sizeof(GL_FBOList));
|
||||
if (result) {
|
||||
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)
|
||||
{
|
||||
|
@ -269,6 +315,7 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
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;
|
||||
|
@ -341,6 +388,22 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags)
|
|||
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;
|
||||
data->renderTarget = NULL;
|
||||
|
||||
/* Set up parameters for rendering */
|
||||
GL_ResetState(renderer);
|
||||
|
@ -402,6 +465,74 @@ GetScaleQuality(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
GL_SetTargetTexture(SDL_Renderer * renderer, SDL_Texture * texture)
|
||||
{
|
||||
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
|
||||
|
||||
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) {
|
||||
if (data->renderTarget != NULL) {
|
||||
data->renderTarget = NULL;
|
||||
renderer->viewport = data->viewport_copy;
|
||||
data->glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
data->glMatrixMode(GL_PROJECTION);
|
||||
data->glLoadIdentity();
|
||||
data->glMatrixMode(GL_MODELVIEW);
|
||||
data->glLoadIdentity();
|
||||
data->glViewport(renderer->viewport.x, renderer->viewport.y, renderer->viewport.w, renderer->viewport.h);
|
||||
data->glOrtho(0.0, (GLdouble) renderer->viewport.w, (GLdouble) renderer->viewport.h, 0.0, 0.0, 1.0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (renderer != texture->renderer) return -1;
|
||||
if (data->renderTarget==NULL) {
|
||||
// Keep a copy of the default viewport to restore when texture==NULL
|
||||
data->viewport_copy = renderer->viewport;
|
||||
}
|
||||
|
||||
|
||||
texturedata = (GL_TextureData *) texture->driverdata;
|
||||
if (!texturedata) {
|
||||
if (texture->native && texture->native->driverdata) {
|
||||
texture = texture->native;
|
||||
texturedata = texture->driverdata;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
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->renderTarget = texture;
|
||||
renderer->viewport.x = 0;
|
||||
renderer->viewport.y = 0;
|
||||
renderer->viewport.w = texture->w;
|
||||
renderer->viewport.h = texture->h;
|
||||
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)
|
||||
{
|
||||
|
@ -446,10 +577,17 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -1013,6 +1151,13 @@ GL_DestroyRenderer(SDL_Renderer * renderer)
|
|||
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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue