首页 > 代码库 > SDL2源代码分析4:纹理(SDL_Texture)
SDL2源代码分析4:纹理(SDL_Texture)
SDL播放视频的代码流程如下所示。
初始化:
SDL_Init(): 初始化SDL。循环渲染数据:
SDL_CreateWindow(): 创建窗口(Window)。
SDL_CreateRenderer(): 基于窗口创建渲染器(Render)。
SDL_CreateTexture(): 创建纹理(Texture)。
SDL_UpdateTexture(): 设置纹理的数据。上篇文章分析了该流程中的第3个函数SDL_CreateRenderer()。本文继续分析该流程中的第4个函数SDL_CreateTexture()。
SDL_RenderCopy(): 纹理复制给渲染器。SDL_RenderPresent(): 显示。
SDL_Texture
SDL_Texture结构定义了一个SDL中的纹理。如果直接使用SDL2编译好的SDK的话,是看不到SDL_Texture的内部结构的。有关它的定义在头文件中只有一行代码,如下所示。
/** * \brief An efficient driver-specific representation of pixel data */ struct SDL_Texture; typedef struct SDL_Texture SDL_Texture;
在源代码工程中可以看到SDL_Texture的定义,位于render\SDL_sysrender.h文件中。它的定义如下。
/* Define the SDL texture structure */ struct SDL_Texture { const void *magic; Uint32 format; /**< The pixel format of the texture */ int access; /**< SDL_TextureAccess */ int w; /**< The width of the texture */ int h; /**< The height of the texture */ int modMode; /**< The texture modulation mode */ SDL_BlendMode blendMode; /**< The texture blend mode */ Uint8 r, g, b, a; /**< Texture modulation values */ SDL_Renderer *renderer; /* Support for formats not supported directly by the renderer */ SDL_Texture *native; SDL_SW_YUVTexture *yuv; void *pixels; int pitch; SDL_Rect locked_rect; void *driverdata; /**< Driver specific texture representation */ SDL_Texture *prev; SDL_Texture *next; };
可以看出其中包含了一个“纹理”所具备的各种属性。下面来看看如何创建这个SDL_Texture。
SDL_CreateTexture()
函数简介
使用SDL_CreateTexture()基于渲染器创建一个纹理。SDL_CreateTexture()的定义如下。SDL_Texture * SDLCALL SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h);
参数的含义如下。
renderer:目标渲染器。
format :纹理的格式。后面会详述。access :可以取以下值(定义位于SDL_TextureAccess中)
SDL_TEXTUREACCESS_STATIC :变化极少SDL_TEXTUREACCESS_STREAMING :变化频繁
SDL_TEXTUREACCESS_TARGET :暂时没有理解
w :纹理的宽
h :纹理的高
创建成功则返回纹理的ID,失败返回0。
函数调用关系图
SDL_ CreateTexture ()关键函数的调用关系可以用下图表示。
上面的图片不太清晰,更清晰的图片上传到了相册里面:
http://my.csdn.net/leixiaohua1020/album/detail/1793543
把相册里面的图片保存下来就可以得到清晰的图片了。
源代码分析
SDL_CreateTexture()的源代码位于render\SDL_render.c中。如下所示。
SDL_Texture * SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h) { SDL_Texture *texture; CHECK_RENDERER_MAGIC(renderer, NULL); if (!format) { format = renderer->info.texture_formats[0]; } if (SDL_ISPIXELFORMAT_INDEXED(format)) { SDL_SetError("Palettized textures are not supported"); return NULL; } if (w <= 0 || h <= 0) { SDL_SetError("Texture dimensions can‘t be 0"); return NULL; } if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) || (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) { SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height); return NULL; } texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture)); if (!texture) { SDL_OutOfMemory(); return NULL; } texture->magic = &texture_magic; texture->format = format; texture->access = access; texture->w = w; texture->h = h; texture->r = 255; texture->g = 255; texture->b = 255; texture->a = 255; texture->renderer = renderer; texture->next = renderer->textures; if (renderer->textures) { renderer->textures->prev = texture; } renderer->textures = texture; if (IsSupportedFormat(renderer, format)) { if (renderer->CreateTexture(renderer, texture) < 0) { SDL_DestroyTexture(texture); return 0; } } else { texture->native = SDL_CreateTexture(renderer, GetClosestSupportedFormat(renderer, format), access, w, h); if (!texture->native) { SDL_DestroyTexture(texture); return NULL; } /* Swap textures to have texture before texture->native in the list */ texture->native->next = texture->next; if (texture->native->next) { texture->native->next->prev = texture->native; } texture->prev = texture->native->prev; if (texture->prev) { texture->prev->next = texture; } texture->native->prev = texture; texture->next = texture->native; renderer->textures = texture; if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { texture->yuv = SDL_SW_CreateYUVTexture(format, w, h); if (!texture->yuv) { SDL_DestroyTexture(texture); return NULL; } } else if (access == SDL_TEXTUREACCESS_STREAMING) { /* The pitch is 4 byte aligned */ texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3); texture->pixels = SDL_calloc(1, texture->pitch * h); if (!texture->pixels) { SDL_DestroyTexture(texture); return NULL; } } } return texture; }
从源代码中可以看出,SDL_CreateTexture()的大致流程如下。
1. 检查输入参数的合理性。例如像素格式是否支持,宽和高是否小于等于0等等。
2. 新建一个SDL_Texture。调用SDL_calloc()(实际上就是calloc())为新建的SDL_Texture分配内存。
3. 调用SDL_Render的CreateTexture()方法创建纹理。这一步是整个函数的核心。
下面我们详细看一下几种不同的渲染器的CreateTexture()的方法。
1. Direct3D
Direct3D 渲染器中对应CreateTexture()的函数是D3D_CreateTexture(),它的源代码如下所示(位于render\direct3d\SDL_render_d3d.c)。static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { D3D_RenderData *renderdata = http://www.mamicode.com/(D3D_RenderData *) renderer->driverdata;>
从代码中可以看出,该函数调用了Direct3D的API函数IDirect3DDevice9_CreateTexture()创建了一个纹理。2. OpenGL
OpenGL渲染器中对应CreateTexture()的函数是GL_CreateTexture (),它的源代码如下所示(位于render\opengl\SDL_render_gl.c)。
static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { GL_RenderData *renderdata = http://www.mamicode.com/(GL_RenderData *) renderer->driverdata;>
从代码中可以看出,该函数调用了OpenGL的API函数glGenTextures(),glBindTexture()创建了一个纹理。并且使用glTexParameteri()设置了有关的一些参数。在这里有一点需要注意,在OpenGL渲染器中,如果输入像素格式是YV12或者IYUV,就会使用3个纹理。
3. Software
Software渲染器中对应CreateTexture()的函数是SW_CreateTexture (),它的源代码如下所示(位于render\software\SDL_render_sw.c)。
static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { int bpp; Uint32 Rmask, Gmask, Bmask, Amask; if (!SDL_PixelFormatEnumToMasks (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { return SDL_SetError("Unknown texture format"); } texture->driverdata = http://www.mamicode.com/SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask,>
该函数的源代码还没有详细分析。可以看出其中调用了SDL_CreateRGBSurface()创建了“Surface”。SDL2源代码分析4:纹理(SDL_Texture)