SDL

SDL_CreateTexture、SDL_DestroyTexture

一、SDL_CreateText

在渲染器内创建纹理。

 

语法

SDL_Texture* SDL_CreateTexture(SDL_Renderer* renderer, Uint32 format, int access, int w, int h)

参数

renderer纹理要归属的渲染器
format[像素格式,SDL_PixelFormatenum中的枚举值
access访问方法,SDL_TextureAccess中的枚举值。更多见注释中“支持的access值”
w像素单位的纹理宽度
h像素单位的纹理高度

返回值

如果成功创建,返回指向该纹理的指针,否则NULL。可能失败的原因:1)没有激活的上下文;2)不支持的像素格式;3)指定的宽度或高度超出范围。可调用SDL_GetError获得更多错误信息。

 

范例

<Example>

 

注释

1. 支持的access值

 
SDL_TEXTUREACCESS_STATIC很少修改,不能上锁。修改指的是调用SDL_UpdateTexture修改像素数据
SDL_TEXTUREACCESS_STREAMING经常修改,能上锁。修改概念等同SDL_TEXTUREACCESS_STATIC
SDL_TEXTUREACCESS_TARGET可作为复制时的目标纹理。复制操作指SDL_RenderCopy、SDL_RenderCopyEx

2. 缩放方式(scaleMode)

调用该函数前,可设置SDL_HINT_RENDER_SCALE_QUALITY选择希望的缩放方式。以下表格描述了选择到某个值时的条件。

 使用它的条件
GL_NEAREST没有设置SDL_HINT_RENDER_SCALE_QUALITY,或空,或是nearest
GL_LINEAR除以上之外

 

3. 纹理链表

渲染器用开环双向链表(SDL_Texture* textures)来存储内中纹理。纹理一旦创建,就会被加入链表,删除则从链表中移除。新建纹理被加到链表头部。

 

4. 执行逻辑

  1. 申请一块SDL_Texture大小的内存。
  2. 检查format是否是渲染器能支持的格式。opengl es2支持的第一种式是SDL_PIXELFORMAT_ARGB8888。
  3. 调用CreateTexture,opengs es2时对应的是GLES2_CreateTexture。

接下描述GLES2_CreateTexture函数逻辑。

1. 根据像素格式得到format、type。对SDL_PIXELFORMAT_ARGB8888,它们的值分别是format=GL_RGBA,type = GL_UNSIGNED_BYTE。

2. 创建要挂接到该纹理的私有结构GLES2_TextureData,填充该结构。

字段语义实例
texture_typeGL_TEXTURE_2D固定是GL_TEXTURE_2D
pixel_format来自上面计算出的formatGL_RGBA
pixel_type来自上面计算出的typeGL_UNSIGNED_BYTE
yuv根据格式判断,是IYUV、YV12置1,否则0 
nv12根据格式判断,是NV12、NV21置1,否则0 

3. access==SDL_TEXTUREACCESS_STREAMING,会分配个blob用于存储图像数据,pixel_data指向这个数据块。

4. 初始化该纹理,以下是涉及到的opengl api

glGenTextures(1, &data->texture);
glActiveTexture(GL_TEXTURE0);  // 激活GL_TEXTURE0纹理单元,以便后续的gl调用是这个活动单元。
glBindTexture(data->texture_type, data.texture);
glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); // 如何计算scaleMode见上面的缩放方式
glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL);  // 加载图像数据。像素字段置的是NULL,此时并没有真正上传数据。

5. access==SDL_TEXTUREACCESS_TARGET,会创建帧缓冲区对象fbo。 要注意的是,并不是一个纹理就会创建一个fbo,而是根据尺寸,多少种尺才对应多少个fbo,正因为这个原因,在SDL_DestroyTexture时不执行删除fbo,而是要等到SDL_DestroyRenderer时一并删除。创建fbo会调用以下gl api。

glGenFramebuffers(1, &result->FBO);

 

二、SDL_DestroyTexture

删除指定纹理

语法

void SDL_DestroyTexture(SDL_Texture* texture)

 

参数

texture要删除的纹理

返回值

void

 

范例

<Example>

 

注释

如果该纹理是渲染器的目标纹理,调用SDL_SetRenderTarget把目标纹理置NULL。

从渲染器的纹理链表删除texture对应的节点。纹理链表见SDL_CreateTexture中的“纹理链表”。

 

调用DestroyTexture,opengl es2对应GLES2_DestroyTexture。

void GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
{
	GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
	......
	if (tdata) {
		glDeleteTextures(1, &tdata->texture);
		......
		SDL_free(tdata->pixel_data);
		SDL_free(tdata);
		texture->driverdata = NULL;
	}
}

它不删除fbo,为什么不删见SDL_CreateTexture注释部分的“access==SDL_TEXTUREACCESS_TARGET”。

 

三、SDL_RenderReadPixels

从当前帧缓冲区读像素数据

语法

int SDL_RenderReadPixels(SDL_Renderer* renderer, const SDL_Rect* rect, Uint32 format, void* pixels, int pitch)

参数

renderer要操作的渲染器
rect位在帧缓冲区的矩形,函数目标就是取该矩形块内的像素
format生成的像素数据的格式
pixelsapp须预分配、用于存放生成的像素数据的存储区
pitch生成的像素块的行跨距。[color=Red]不是帧缓冲区的行跨距。

返回值

0表示成功。否则是一个负值,调用SDL_GetError可获得错误的更多信息。

 

范例

surface dst = create_neutral_surface(area.w, area.h);
{
	surface_lock dst_lock(dst);
	uint32_t format = get_neutral_pixel_format().format;
	SDL_RenderReadPixels(get_renderer(), &area, format, dst->pixels, SDL_BYTESPERPIXEL(format) * area.w);
}

读当前帧缓冲区,把area块内像素搬到dst->pixels。dst->pixels中的像素格式是get_neutral_pixel_format().format。

 

注释

这是个非常慢的函数,不要经常调用。怎么个慢法,参考这贴子:[url=http://www.libsdl.cn/bbs/forum.php?mod=viewthread&tid=49&extra=page%3D1]SDL_UpdateTexture、SDL_RenderCopy、SDL_RenderReadPixels的花费时间[/url]

 

窗口帧缓冲区和目标帧缓冲区

SDL_RenderReadPixels支持从两种帧缓冲区读取数据,渲染器的target变量控制了要读取是哪一种。当是目标帧缓冲区时,有一些特殊限定。

  • 目标帧缓冲区对应纹理的像素格式须是4分量、4字节。
  • SDL_RenderReadPixels不会改变像素格式,它直接以纹理格存放在pixels。因为这个原因,参数format其实只要表示这是“4分量、4字节”就行,而pitch总是要等于w*4。

全部评论: 0

    写评论: