音视频开发十七:SDL相关API和结构体

SDL相关API

纹理渲染相关API

SDL_init

SDL_Init 是 SDL 库的初始化函数,作用是初始化 SDL 库并加载所需要的子系统。这个函数必须在使用 SDL 库的其他函数之前被调用。函数定义如下:

int SDL_Init(Uint32 flags)

flags 参数是一个位掩码,用于指定需要初始化的子系统,常用的值包括:

  • SDL_INIT_VIDEO:表示初始化视频子系统,用于创建和管理窗口、渲染器等。
  • SDL_INIT_AUDIO:表示初始化音频子系统,用于播放和录制音频。
  • SDL_INIT_JOYSTICK:表示初始化手柄子系统,用于管理游戏手柄和游戏垫。
  • SDL_INIT_GAMECONTROLLER:表示初始化游戏控制器子系统,用于管理游戏控制器。
  • SDL_INIT_EVENTS:表示初始化事件子系统,用于处理 SDL 应用程序的事件循环和消息队列。

其他可用的子系统包括:SDL_INIT_TIMER、SDL_INIT_HAPTIC、SDL_INIT_SENSOR 等。要使用多个子系统,可以将它们的值进行按位或操作,例如:

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);

函数返回值是一个整数,表示是否初始化成功。如果返回值为 0,则表示初始化成功,否则返回的是一个错误代码,可以通过调用 SDL_GetError() 函数获取相关错误信息。

SDL_CreateWindow

SDL_CreateWindow 是 SDL 库创建窗口的函数,作用是创建一个 SDL 窗口对象,用于显示图形界面。函数定义如下:

SDL_Window* SDL_CreateWindow(const char* title, int x, int y, int w, int h, Uint32 flags)

函数的参数及其说明如下:

  • title:窗口的标题,以零结尾的字符串。

  • x:窗口左上角在屏幕上的水平坐标,如果值为 SDL_WINDOWPOS_CENTERED,则窗口将在屏幕中央显示。

  • y:窗口左上角在屏幕上的竖直坐标,如果值为 SDL_WINDOWPOS_CENTERED,则窗口将在屏幕中央显示。

    x和y设置为SDL_WINDOWPOS_UNDEFINED表示让操作系统自己决定窗口的位置

  • w:窗口的宽度(单位:像素)。

  • h:窗口的高度(单位:像素)。

  • flags:窗口的属性,是 SDL_WindowFlags 枚举类型中的位掩码。常用的属性包括:

    • SDL_WINDOW_SHOWN:创建窗口时立即显示。
    • SDL_WINDOW_RESIZABLE:窗口可以调整大小。
    • SDL_WINDOW_FULLSCREEN:窗口全屏显示(覆盖任务栏等)。
    • SDL_WINDOW_BORDERLESS:窗口无边框,不能调整大小。
    • SDL_WINDOW_ALLOW_HIGHDPI:支持高分辨率显示(用于 Retina 屏幕等)。
    • SDL_WINDOW_OPENGL: 表示使用OpenGL渲染窗口。

返回值是一个 SDL_Window 结构体指针,表示创建的窗口对象。如果创建失败,则返回 NULL,并通过调用 SDL_GetError() 函数获取错误信息。

SDL_CreateWindow 函数只能用于创建基本的窗口对象,如果需要使用 OpenGL 或 Vulkan 渲染图形,需要使用 SDL_CreateWindowAndRenderer 或 SDL_CreateWindowFrom 函数。

SDL_DestroyWindow

SDL_DestroyWindow是SDL2中用于销毁窗口的函数。窗口是一个SDL_Window类型的结构体,包含了模块化各种窗口所需的数据和属性。当我们使用完窗口之后,为了释放内存并避免程序泄漏,需要调用SDL_DestroyWindow函数来销毁窗口。SDL_DestroyWindow函数的函数原型如下:

void SDL_DestroyWindow(SDL_Window* window)

函数参数window为需要销毁的窗口指针。使用该函数后,程序将该窗口及其所有资源从内存中删除,将不再能够使用对该窗口的引用。

SDL_Quit

SDL_Quit 是 SDL 库退出函数,作用是释放 SDL 库占用的资源并退出 SDL 应用程序。函数定义如下:

void SDL_Quit(void)

该函数没有参数,也没有返回值。在调用该函数之后,SDL 应用程序会正常退出。需要注意的是,调用 SDL_Quit 函数后,所有 SDL 窗口、渲染器、音频设备等都会被销毁,应该确保在调用 SDL_Quit 函数前,所有这些对象的资源都被正常释放

在主函数的最后,应该始终调用 SDL_Quit 函数释放 SDL 库占用的资源,示例如下:

int main(int argc, char* argv[])
{
    
    
    // 初始化 SDL 库
    SDL_Init(SDL_INIT_VIDEO);

    // 创建窗口
    SDL_Window* window = SDL_CreateWindow("My Window",
                                          SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                          640, 480, SDL_WINDOW_SHOWN);

    // 等待用户关闭窗口
    bool is_quit = false;
    SDL_Event event;
    while (!is_quit) {
    
    
        while (SDL_PollEvent(&event)) {
    
    
            if (event.type == SDL_QUIT) {
    
    
                is_quit = true;
            }
        }
    }

    // 释放窗口资源并退出 SDL 库
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

在该示例中,先初始化 SDL 库,然后创建一个窗口,并启动主循环等待用户关闭窗口。在窗口关闭后,调用 SDL_DestroyWindow 函数释放窗口资源,并调用 SDL_Quit 函数退出 SDL 应用程序。

SDL_CreateRenderer

SDL_CreateRenderer 是创建 SDL 渲染器(渲染上下文)的函数,函数定义如下:

SDL_Renderer* SDL_CreateRenderer(SDL_Window* window, int index, Uint32 flags)

参数说明:

  • window:SDL 窗口指针,用于关联创建的渲染器对象和窗口。

  • index:渲染器的索引值,决定了渲染器的具体实现,可以传入 -1 使用默认的渲染器。

  • flags:渲染器的配置选项,可以设置渲染模式、硬件加速、缓冲模式等。 传入0表示表示创建一个仅支持软件渲染的渲染器对象,不使用硬件加速。

    SDL_RENDERER_SOFTWARE        // 兼容性模式,使用软件渲染
    SDL_RENDERER_ACCELERATED     // 硬件加速模式,充分利用GPU的硬件加速功能
    SDL_RENDERER_PRESENTVSYNC    // 垂直同步模式,来防止画面撕裂
    SDL_RENDERER_TARGETTEXTURE   // 可以将渲染的内容保存到纹理中
    

    可以使用按位或操作符|将多个选项组合在一起,以满足不同情况下的需求。例如,要创建一个支持硬件加速和垂直同步的渲染器,可以使用以下标志:

    int flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
    

    需要注意的是,没有必要使用所有类型的标志,具体取决于您的需求。例如,如果您不是大量使用纹理,并且不需要实时的VSync,那么使用默认的软件渲染器也是可以的。

函数返回值为 SDL_Renderer 类型的指针,表示创建成功的渲染器对象。如果创建失败,则返回 NULL。

示例代码:

SDL_Window* window = SDL_CreateWindow("my window", SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

在上面的示例中,我们先创建了一个 SDL 窗口,然后通过 SDL_CreateRenderer 函数创建了一个渲染器对象,参数中使用了默认的索引值和硬件加速选项。创建完毕后,我们就可以通过该渲染器对象在 SDL 窗口上进行绘制操作了。需要注意的是,我们需要在程序结束前调用 SDL_DestroyRenderer 函数释放掉渲染器对象释放确保程序正常退出。

SDL_DestroyRenderer

SDL_DestroyRenderer是SDL2中用于销毁渲染器的函数。当我们不再需要渲染器时,为了释放内存并避免程序泄漏,需要调用SDL_DestroyRenderer函数来销毁渲染器。SDL_DestroyRenderer函数的函数原型如下:

void SDL_DestroyRenderer(SDL_Renderer* renderer)

函数参数renderer为需要销毁的渲染器指针。使用该函数后,程序将该渲染器及其所有资源从内存中删除,将不再能够使用对该渲染器的引用。

SDL_SetRenderDrawColor

SDL_SetRenderDrawColor 是一个用于设置 SDL2 渲染器绘制颜色的函数

函数原型:

int SDL_SetRenderDrawColor(SDL_Renderer* renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a);

参数说明:

  • renderer:渲染器指针。
  • r:红色通道,范围为 0-255。
  • g:绿色通道,范围为 0-255。
  • b:蓝色通道,范围为 0-255。
  • a:Alpha 通道,范围为 0-255,0 表示完全透明,255 表示完全不透明。

函数作用:

设置渲染器的绘制颜色,即下一次绘制将使用的颜色。例如,如果将绘制颜色设置为红色(r=255,g=0,b=0,a=255),则下一次调用 SDL_RenderDrawRect 将绘制一个红色的矩形。

注意:设置绘制颜色只是确定了使用哪种颜色进行绘制,但并不实际进行绘制。要在渲染目标上使用设置好的颜色进行绘制,必须使用绘制函数(例如 SDL_RenderDrawLine、SDL_RenderDrawRect 等)进行调用。

示例:

SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); // 将绘制颜色设置为红色
SDL_RenderDrawRect(renderer, &rect); // 使用红色绘制矩形

此代码将设置渲染器的绘制颜色为红色,并使用 SDL_RenderDrawRect 函数绘制一个红色矩形。此绘制操作将在调用 SDL_RenderPresent 函数后显示在屏幕上。

SDL_RenderClear

就是用设置好的颜色(默认黑色)来 “清空” 渲染目标。可以这样理解,我先清空渲染目标中所有的颜色,然后用绘制的颜色填充渲染目标。也可以理解为一个刷子,刷子比较特殊,用设置的颜色,刷满整个渲染目标。

示例代码如下:

SDL_Window* window = SDL_CreateWindow("SDL Render Clear Example",
                                      SDL_WINDOWPOS_CENTERED,
                                      SDL_WINDOWPOS_CENTERED,
                                      640, 480,
                                      SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

/SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);//设置绘制颜色,白色
SDL_RenderClear(renderer);// 清空渲染目标,不指定绘制颜色的话,默认为黑色,由于上述设置,所以填充为白色

// 设置颜色为红色
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);

// 绘制一个矩形
SDL_Rect rect = {
    
    100, 100, 200, 200};
SDL_RenderFillRect(renderer, &rect);

// 更新屏幕
SDL_RenderPresent(renderer);

SDL_Delay(2000);

SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);

上面的示例代码创建了一个窗口和一个使用硬件加速的渲染器对象,然后调用 SDL_RenderClear 函数清空了渲染目标,接着设置了颜色为红色,并在屏幕上绘制了一个矩形。最后调用 SDL_RenderPresent 函数更新屏幕显示,使得我们能够看到绘制结果,白色的屏幕上绘制了一个红色的矩形。执行完毕后,销毁渲染器和窗口,释放相应的资源。

SDL_CreateTexture

SDL_CreateTexture 是 SDL2 中用来创建 SDL_Texture(纹理对象) 的函数,从一个已有的 SDL_Renderer 以及一个指定的格式、渲染宽高创建。该函数的原型如下:

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

参数列表:

  • rendererSDL_Renderer 指针,创建 SDL_Texture 时使用的渲染器;

  • formatUint32,用来指定纹理像素格式(即每个像素需要多少个字节来表示)。SDL中提供了多种像素格式,包括 RGB、RGBA、ARGB、BGR、BGRA、ABGR等。其中RGBA格式最为常见,它使用4个字节表示每个像素,分别代表红色、绿色、蓝色和 alpha(透明度)。;

    Uint32 textureFormat = SDL_PIXELFORMAT_RGBA8888;
    SDL_Texture* texture = SDL_CreateTexture(renderer, textureFormat, SDL_TEXTUREACCESS_STREAMING, 640, 480);
    

    其中,SDL_PIXELFORMAT_RGBA8888是SDL支持的32位RGBA像素格式之一,表示每个像素由4个八位字节的分量组成,顺序分别为红、绿、蓝和alpha分量。通过将textureFormat设置为SDL_PIXELFORMAT_RGBA8888,我们可以创建一个RGBA8888格式的纹理,从而在屏幕上渲染出具有透明效果的图像。

  • accessint,指定创建的纹理的访问方式,指定纹理的访问方式,有以下几种选项:

    • SDL_TEXTUREACCESS_STATIC:纹理被固定分配在显存中,不可修改。
    • SDL_TEXTUREACCESS_STREAMING:纹理被用于频繁更新。显存与CPU共享,可以通过lock/unlock操作来完成。
    • SDL_TEXTUREACCESS_TARGET:纹理可以当做渲染目标,贴到其他纹理或窗口的面上使用。
  • wint,创建纹理的宽度;

  • hint,创建纹理的高度。

返回值:返回创建失败时为 NULL,否则为一个 SDL_Texture 指针。

SDL_UpdateTexture

​ SDL_UpdateTexture()是SDL2中用于更新纹理的函数。它用于将位图内容复制到创建的纹理中。每次更新纹理时都会替换整个纹理。要部分更新,请使用SDL_UpdateTextureRect()。

函数原型:

int SDL_UpdateTexture(SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)

参数解析:

  • texture: 指向要更新的纹理的指针。
  • rect: 更新的纹理的矩形区域。如果为NULL,则默认为整个纹理。
  • pixels: 要复制到纹理中的像素数据的指针。
  • pitch: 像素数据的长度(字节数)。

返回值:

  • 如果成功,则返回0,否则返回-1,并设置SDL_GetError()的错误信息。

**使用SDL_CreateTexture()创建纹理时,必须使用SDL_TEXTUREACCESS_STREAMING标志,这会告诉SDL它需要使用带有动态修改的纹理。**这意味着可能需要重复调用SDL_UpdateTexture()函数来更新图像。常见的用例是流式媒体或视频。

SDL_CreateTexture函数的使用说明:

  1. 当纹理是静态的,即不需要频繁更新时,建议使用SDL_TEXTUREACCESS_STATIC访问方式。这种方式可以保证纹理的渲染速度。
  2. 当纹理需要频繁更新时,建议使用SDL_TEXTUREACCESS_STREAMING访问方式,它支持lock/unlock操作来更新纹理内容。
  3. 当纹理需要被用于渲染目标时,建议使用SDL_TEXTUREACCESS_TARGET访问方式,它支持使用纹理作为渲染目标,并将纹理与窗口配合使用。

**需要注意的是:**创建纹理之后需要通过 SDL_DestroyTexture 函数销毁纹理,避免出现内存泄漏。

SDL_UpdateYUVTexture

SDL_UpdateYUVTexture() 是SDL库中用于更新 YUV 格式的纹理的函数。

函数原型如下:

int SDL_UpdateYUVTexture(SDL_Texture* texture, const SDL_Rect* rect, const Uint8* dataY, int pitchY, const Uint8* dataU, int pitchU, const Uint8* dataV, int pitchV)

参数说明:

  • texture: 需要更新的纹理。
  • rect: 要更新的矩形区域,为NULL表示更新整个纹理。
  • dataY, dataU, dataV: YUV 数据指针。
  • pitchY, pitchU, pitchV: YUV 数据每行的字节数,通常为 width。

SDL_UpdateYUVTexture()函数可以用于将 YUV 数据更新到 SDL 窗口中进行显示。

SDL_DestroyTexture

SDL_DestroyTexture是SDL2中用于销毁纹理的函数。具体的函数原型如下:

void SDL_DestroyTexture(SDL_Texture* texture)

参数解释:

  • texture:要销毁的纹理。

使用SDL_DestroyTexture函数可以释放创建纹理时所使用的资源,包括纹理对象本身以及对应的显存资源。如果不及时销毁纹理,那么程序会在占用大量资源的情况下运行,极容易导致性能问题。

使用SDL_DestroyTexture的时机:

通常情况下,使用SDL_CreateTexture创建了纹理之后,在退出之前通过SDL_DestroyTexture来进行销毁即可。如果创建了大量纹理,应该在不需要使用这些纹理时及时销毁,以提高系统的运行效率。

SDL_RenderDrawRect

SDL_RenderDrawRect函数可以在渲染目标上绘制一个矩形。其原型如下:

int SDL_RenderDrawRect(SDL_Renderer* renderer, const SDL_Rect* rect);

其中,renderer是渲染器指针,rect是一个SDL_Rect结构体指针,表示绘制的矩形。SDL_Rect结构体包含了四个整型变量,分别表示矩形的左上角坐标和宽度、高度。

调用SDL_RenderDrawRect函数后,渲染器会在渲染目标上绘制一个由参数rect指定的矩形,矩形的边框为当前设置的绘制颜色,填充区域为空。

SDL_RenderFillRect

SDL_RenderFillRect函数可以在渲染目标上绘制一个填充矩形。它使用的参数和SDL_RenderDrawRect类似,区别在于绘制的矩形会被填充,而不是仅仅绘制边框。

其原型如下:

int SDL_RenderFillRect(SDL_Renderer* renderer, const SDL_Rect* rect);

其中,renderer是渲染器指针,rect是一个SDL_Rect结构体指针,表示绘制的矩形。

调用SDL_RenderFillRect函数后,渲染器会在渲染目标上绘制一个由参数rect指定的填充矩形,矩形的颜色为当前设置的绘制颜色。

SDL_RenderCopy

SDL_RenderCopy是SDL2中用于在指定目标上渲染纹理的函数。它的具体函数原型如下:

int SDL_RenderCopy(SDL_Renderer* renderer, SDL_Texture* texture, const SDL_Rect* srcrect, const SDL_Rect* dstrect);

函数参数解释:

  • renderer:渲染器,用于指定渲染目标。
  • texture:纹理对象,即要被渲染的纹理。
  • srcrect:源矩形,用于指定从纹理中渲染哪部分。NULL表示全部
  • dstrect:目标矩形,用于指定在渲染目标中的位置和大小。NULL表示全部

使用SDL_RenderCopy函数,可以在指定的渲染目标上渲染纹理,并在目标矩形中指定纹理所在的位置和大小。一般在程序基于纹理进行图像渲染时,使用SDL_RenderCopy函数可以将纹理渲染到渲染器上,以实现图像绘制的效果。

值得注意的是,SDL_RenderCopy中的四个参数都必须指定,如果传递了NULL,则表示使用纹理的默认值。在实际使用的过程中,可以采用指定源矩形和目标矩形中的一些小技巧,例如将源矩形和目标矩形的数据类型转换为浮点型,以方便进行缩放和移动操作,还可以利用SDL_Rect结构体的裁切特性,仅渲染纹理的局部部分

SDL_SetRenderTarget

SDL_SetRenderTarget 是 SDL2 中一个用于设置渲染目标(给谁渲染)的函数,在SDL中,渲染目标可能是默认的窗口,也可能是已创建的纹理。

它的原型如下:

int SDL_SetRenderTarget(SDL_Renderer*   renderer,
                        SDL_Texture*    texture);

参数列表:

  • rendererSDL_Renderer 指针,设置渲染目标使用的渲染器;
  • textureSDL_Texture 指针,用来作为渲染目标的纹理。

如果将texture设为NULL,则会将渲染目标还原回默认窗口。使用SDL_SetRenderTarget函数可以将纹理设置为渲染目标,然后可以将其他纹理或图像渲染到此纹理上。同时,纹理可以具有透明度,方便透明效果的实现。

返回值:函数执行成功则返回 0,否则返回 -1。

SDL_SetRenderTarget函数的使用:

  1. 调用SDL_CreateTexture函数创建一个纹理对象。
  2. 使用SDL_SetRenderTarget函数设置要渲染的纹理。
  3. 使用其他渲染函数将图像渲染到纹理上。
  4. 调用SDL_RenderCopy函数将纹理渲染到窗口上。

值得注意的是,只要设置了渲染目标,那么在渲染结束前,一定需要使用SDL_SetRenderTarget将渲染目标还原回默认窗口,否则后续渲染的图像就会出现问题。

SDL_RenderPresent

函数用于更新渲染目标的显示。

函数原型:

void SDL_RenderPresent(SDL_Renderer* renderer);

参数说明:

  • renderer:渲染器指针。

函数作用:

将当前的渲染目标(通常是屏幕)上的绘制结果刷新到显示器上,即更新渲染器,使其显示最新的绘制结果

在每一次渲染操作后需要调用 SDL_RenderPresent 函数来在屏幕上显示所绘制的内容。如果没有调用此函数,程序将看不到任何绘制的内容。

示例:

// 绘制完所有的图像后,需要调用 SDL_RenderPresent 函数将绘制结果更新到屏幕上
SDL_RenderPresent(renderer);

此代码将渲染器上的所有绘制结果更新到屏幕上

SDL_AddTimer

SDL_AddTimer函数是SDL中的定时器函数,用于注册回调函数并创建一个定时器

SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void* param);

参数说明:

  • interval:定时器触发时间间隔(毫秒)
  • callback:回调函数指针,用于处理定时器触发时的事件
  • param:回调函数的参数,可以为NULL

返回值:

  • 成功:返回定时器ID
  • 失败:返回0

每隔interval,触发callback,并把param传递过去。

SDL事件相关API

DL_Event 是SDL库中使用的一个数据结构,用于表示系统中发生的事件。一个事件可以是键盘按键、鼠标移动、游戏手柄移动、窗口事件等。SDL_Event 结构包含有关事件类型、事件发生时间和事件参数的详细信息。

SDL_Event 结构具有以下成员:

  • type:表示事件类型的整数。
    • SDL_QUIT:表示退出事件,当用户关闭窗口或按下键盘上的 Alt + F4 或 Cmd + Q 组合键时会触发该事件。
    • SDL_KEYDOWN / SDL_KEYUP:表示键盘按键事件,当用户按下或释放键盘上的按键时会触发该事件。
    • SDL_MOUSEMOTION / SDL_MOUSEBUTTONDOWN / SDL_MOUSEBUTTONUP:表示鼠标事件,当用户移动鼠标或按下、释放鼠标按钮时会触发该事件。
    • SDL_WINDOWEVENT:表示窗口事件,当窗口状态发生变化时会触发该事件,例如窗口大小发生变化,窗口获得或失去焦点等。
    • SDL_JOYAXISMOTION / SDL_JOYBALLMOTION / SDL_JOYHATMOTION / SDL_JOYBUTTONDOWN / SDL_JOYBUTTONUP / SDL_JOYDEVICEADDED / SDL_JOYDEVICEREMOVED:表示游戏手柄事件,当游戏手柄状态发生变化时会触发该事件,例如手柄移动、按下、释放按钮等。
    • SDL_CONTROLLERAXISMOTION / SDL_CONTROLLERBUTTONDOWN / SDL_CONTROLLERBUTTONUP / SDL_CONTROLLERDEVICEADDED / SDL_CONTROLLERDEVICEREMOVED:表示控制器事件,当控制器状态发生变化时会触发该事件,例如控制器移动、按下、释放按钮等。
    • SDL_USEREVENT:表示用户自定义事件,当应用程序调用 SDL_PushEvent 函数将自定义事件添加到事件队列时,会触发该事件。
  • timestamp:表示事件发生时间的 Uint32 类型数值。
  • window:表示事件所属的 SDL_Window 数据指针。
  • key:表示键盘事件的 SDL_KeyboardEvent 数据结构。
  • motion:表示鼠标移动事件的 SDL_MouseMotionEvent 数据结构。
  • button:表示鼠标按钮事件的 SDL_MouseButtonEvent 数据结构。
  • wheel:表示鼠标滚轮事件的 SDL_MouseWheelEvent 数据结构。
  • jaxis:表示游戏手柄轴移动事件的 SDL_JoyAxisEvent 数据结构。
  • jball:表示游戏手柄球移动事件的 SDL_JoyBallEvent 数据结构。
  • jbutton:表示游戏手柄按钮事件的 SDL_JoyButtonEvent 数据结构。
  • jdevice:表示游戏手柄设备事件的 SDL_JoyDeviceEvent 数据结构。
  • caxis:表示游戏手柄轴移动事件的 SDL_ControllerAxisEvent 数据结构。
  • cbutton:表示游戏手柄按钮事件的 SDL_ControllerButtonEvent 数据结构。
  • cdevice:表示游戏手柄设备事件的 SDL_ControllerDeviceEvent 数据结构。
  • quit:表示退出事件的 SDL_QuitEvent 数据结构。
  • user:表示用户自定义事件的 SDL_UserEvent 数据结构。

通过处理 SDL_Event 结构数据,应用程序可以处理用户输入和系统事件,以产生交互行为。

SDL_PollEvent()

SDL_PollEvent()是SDL事件处理库中的一个函数,用于从事件队列中轮询(一直循环)事件并返回。它可以用于捕获用户输入,控制游戏状态等。

在调用SDL_PollEvent()函数时,它会检查SDL事件队列中是否有事件,并将此事件从队列顶部弹出并返回。如果事件队列为空,则该函数将立即返回0。如果有事件,则该函数将返回1,并将事件结构体填充到指定的SDL_Event结构体中。根据事件类型的不同,SDL_Event结构体的不同字段将被填充。

以下是一个简单的SDL_PollEvent()函数的示例,它只处理鼠标事件:

SDL_Event event;

while (SDL_PollEvent(&event)) {
    
    
    switch (event.type) {
    
    
        case SDL_MOUSEMOTION:
            // 处理鼠标移动事件
            break;
        case SDL_MOUSEBUTTONDOWN:
            // 处理鼠标按下事件
            break;
        case SDL_MOUSEBUTTONUP:
            // 处理鼠标释放事件
            break;
        default:
            break;
    }
}

由于SDL_PollEvent()函数是轮询事件队列的,因此它不会占用大量资源,可在循环中反复使用。但要注意,如果在事件处理期间执行某些任务会导致轮询事件的延迟。

SDL_WaitEvent

SDL_WaitEvent()是SDL事件处理库中的一个函数,用于等待并获取下一个事件。它可用于阻塞程序执行,直到有事件发生。

在调用SDL_WaitEvent()函数时,它会检查事件队列中是否有事件。如果事件队列为空,则该函数会阻塞当前线程并等待事件的到来。如果队列中有事件,则该函数将该事件弹出队列并返回一个非零值。与SDL_PollEvent()不同,不需要指定要轮询的事件类型。

以下是一个简单的SDL_WaitEvent()函数的示例,它等待并处理一个QUIT事件。QUIT事件表示用户关闭窗口或程序正在退出:

SDL_Event event;

while (SDL_WaitEvent(&event)) {
    if (event.type == SDL_QUIT) {
        // 处理退出事件
        break;
    }
}

需要注意的是,SDL_WaitEvent()函数会阻塞当前线程,因此如果等待事件的时间过长,将会导致程序停滞,并不利于程序的执行。建议在需要响应用户输入的情况下使用SDL_WaitEvent(),在不需要响应事件的情况下建议使用SDL_PollEvent()。

SDL 线程相关API

主线程和子线程对共享变量互斥操作示例代码:


	#include <SDL.h>
	#include <stdio.h>
	
	SDL_mutex *mutex = NULL;
	SDL_cond *cond = NULL;
	
	int thread_work(void *arg) {
    
    
	
	  printf("Thread-2 Lock Mutex Start\n");
	  SDL_LockMutex(mutex);
	  printf("Thread-2 Lock Mutex Success\n");
	
	  printf("Thread-2 Working with Mutex\n");
	  sleep(4);
	
	  printf("Thread-2 Wait Condition Start\n");
	  SDL_CondWait(cond, mutex);
	  printf("Thread-2 Wait Condition Success\n");
	
	  printf("Thread-2 Unlock Mutex\n");
	  SDL_UnlockMutex(mutex);
	
	  printf("Thread-2 Finish\n");
	
	  return 0;
	}
	
	#undef main
	int main() {
    
    
	
	  mutex = SDL_CreateMutex();
	  cond = SDL_CreateCond();
	
	  SDL_Thread *t = SDL_CreateThread(thread_work, "Thread-2", NULL);
	
	  printf("Thread-1 Working\n");
	  sleep(2);
	
	  printf("Thread-1 Lock Mutex Start\n");
	  SDL_LockMutex(mutex);
	  printf("Thread-1 Lock Mutex Success\n");
	
	  printf("Thread-1 Working with Mutex\n");
	  sleep(2);
	
	  printf("Thread-1 Send Condition Signal\n");
	  SDL_CondSignal(cond);
	
	  printf("Thread-1 Working with Mutex\n");
	  sleep(2);
	
	  printf("Thread-1 Unlock Mutex\n");
	  SDL_UnlockMutex(mutex);
	
	  printf("Thread-1 Wait Thread-2 Finish Start\n");
	  SDL_WaitThread(t, NULL);
	  printf("Thread-1 Wait Thread-2 Finish Success\n");
	
	  printf("Thread-1 Destroy Mutex Start\n");
	  printf("Thread-1 Destroy Condition Start\n");
	  SDL_DestroyMutex(mutex);
	  SDL_DestroyCond(cond);
	  printf("Thread-1 Destroy Mutex Success\n");
	  printf("Thread-1 Destroy Condition Success\n");
	
	  return 0;
	}


SDL_CreateThread

SDL_CreateThread函数用于创建一个新线程。其原型如下:

SDL_Thread* SDL_CreateThread(SDL_ThreadFunction fn, const char* name, void* data);

其中,fn是一个线程执行的函数,函数指针的定义是:

typedef int (*SDL_ThreadFunction)(void* data);

它接收一个void指针,指向当前线程的参数数据;

name是线程名称;

data是传递给线程函数的数据参数。

调用SDL_CreateThread函数后,将会创建一个新的线程,并在其中执行参数fn所指定的线程执行函数。创建完成后,函数会返回一个指向SDL_Thread结构体的指针,这个结构体包含了线程的ID和名称等信息。

示例代码:

// 线程执行函数,接收一个void指针作为参数
int threadFunc(void *data)
{
    
    
    // 要执行的线程任务
    return 0;
}

// 在主线程中创建一个新线程
SDL_Thread* thread = SDL_CreateThread(threadFunc, "MyThread", NULL);

在这个示例中,我们通过SDL_CreateThread函数在主线程中创建了一个新线程,用于执行线程执行函数threadFunc。在本例中,函数没有传递任何参数,所以最后的NULL表示不传递数据参数。

SDL_WaitThread

SDL_WaitThread是SDL库提供的一个线程等待函数,它的作用是等待指定的线程执行完毕。函数原型如下:

int SDL_WaitThread(SDL_Thread* thread, int* status);

该函数的第一个参数是SDL_Thread类型的指针,表示要等待的线程。第二个参数是一个整型指针,用于存储线程的退出状态。函数的返回值为0表示线程已正常退出,其他值表示错误。

SDL_WaitThread函数会挂起当前线程,等待指定的线程执行完毕,并接收指定线程的返回状态。如果线程已经退出,函数会立刻返回,并将线程的退出状态存入status指针所指的内存中。

SDL_CreateMutex

SDL_CreateMutex() 是SDL库中用于创建互斥锁(mutex)的函数。互斥锁是一种用于保护共享资源的同步原语,它可以确保同一时间内只有一个线程访问共享资源,以避免数据竞争和并发问题。

SDL_CreateMutex() 的函数原型如下:

SDL_mutex* SDL_CreateMutex(void)

该函数不需要任何参数,它返回一个指向新创建互斥锁的指针(SDL_mutex*类型),如果创建失败则返回 NULL。

SDL_LockMutex

SDL_LockMutex() 是SDL库中用于锁定互斥锁(mutex)的函数

SDL_LockMutex() 的函数原型如下:

int SDL_LockMutex(SDL_mutex* mutex)

该函数的参数为互斥锁指针(SDL_mutex*类型),函数返回一个整型值,表示函数调用的结果。若函数成功锁定互斥锁,则返回0;否则返回错误代码。

当一个线程执行 SDL_LockMutex() 函数时,如果互斥锁当前没有被其他线程锁定,则该线程会立即获得互斥锁并可以访问受保护的共享资源。如果互斥锁当前已经被其他线程锁定,那么该线程会一直阻塞等待直到互斥锁被释放并可以被该线程获得为止。

需要注意的是,在使用互斥锁时,要遵循“谁申请谁释放”的原则,即使用 SDL_LockMutex() 函数锁定互斥锁的线程必须在访问完共享资源后使用 SDL_UnlockMutex() 函数释放互斥锁,否则其他线程将无法获得该锁访问共享资源。

下面是一个简单的示例代码,展示了如何使用 SDL_LockMutex() 函数锁定互斥锁,以避免多线程下的共享资源的并发问题:

#include <SDL.h>

// 定义一个全局变量作为共享的资源
int shared_data = 0;

SDL_mutex* mutex;

void some_function(void) {
    
    
    // 等待并锁定互斥锁
    SDL_LockMutex(mutex);

    // 访问受保护的共享资源
    shared_data += 1;

    // 解锁互斥锁
    SDL_UnlockMutex(mutex);
}

int main() {
    
    
    // 初始化SDL库
    SDL_Init(SDL_INIT_EVERYTHING);

    // 创建互斥锁
    mutex = SDL_CreateMutex();

    // 启动多个线程访问共享资源
    // ...

    // 最后释放互斥锁
    SDL_DestroyMutex(mutex);

    // 退出SDL库
    SDL_Quit();
    return 0;
}

SDL_UnlockMutex

SDL_LockMutex() 是SDL库中用于释放互斥锁(mutex)的函数

SDL_UnlockMutex 函数的函数原型为:

int SDL_UnlockMutex(SDL_mutex* mutex);

SDL_DestroyMutex

SDL_LockMutex() 是SDL库中用于销毁互斥锁(mutex)的函数

SDL_DestroyMutex 函数的函数原型为:

void SDL_DestroyMutex(SDL_mutex* mutex);

SDL_CreateCond

SDL_CreateCond() 是SDL库中用于创建条件变量(condition variable)的函数。条件变量是一种线程间同步原语,它允许一个线程等待另一个线程满足某个条件后再继续执行,从而更好地控制线程的执行顺序和并发性。

SDL_CreateCond() 的函数原型如下:

SDL_cond* SDL_CreateCond(void)

该函数没有参数,返回一个指向新创建条件变量的指针(SDL_cond*类型),如果创建失败则返回 NULL。

SDL_CondSignal

SDL_CondSignal() 是SDL库中用于发送条件变量(condition variable)信号的函数。

SDL_CondSignal() 的函数原型如下:

int SDL_CondSignal(SDL_cond* cond)

该函数的参数为条件变量指针(SDL_cond*类型),函数返回一个整型值,表示函数调用的结果。若函数成功发送条件变量信号,则返回0;否则返回错误代码。

SDL_CondWait

SDL_CondWait() 是SDL库中用于等待条件变量(condition variable)信号的函数

DL_CondWait() 函数允许线程在等待条件变量时解锁互斥锁,从而让其他线程可以继续访问共享资源

SDL_CondWait() 的函数原型如下:

int SDL_CondWait(SDL_cond* cond, SDL_mutex* mutex)

该函数的参数为条件变量指针(SDL_cond类型)和互斥锁指针(SDL_mutex类型),函数返回一个整型值,表示函数调用的结果。如果条件变量成功地接收到信号,则返回0;否则返回错误代码。

当一个线程调用 SDL_CondWait() 函数时,它会先解锁互斥锁(把自己的锁解开,所以使用SDL_CondWait函数之前,必须先获取到锁),然后阻塞,一直等待条件变量的信号(SDL_CondSignal或SDL_CondBroadcast),直到信号被发送给该条件变量。当线程接收到信号后,被唤醒,这时候它会重新获取互斥锁(重新获取就是尝试获取,如果其他线程不释放该锁,即使收到信号也不会向下执行。),以访问共享资源。

SDL_DestroyCond

SDL_DestroyCond() 是SDL库中用于销毁条件变量(condition variable)的函数。

SDL_DestroyCond() 的函数原型如下:

void SDL_DestroyCond(SDL_cond* cond)

该函数的参数为条件变量指针(SDL_cond*类型),没有返回值。在销毁条件变量时,需要先保证该条件变量没有被任何线程在等待,然后将其释放掉。

SDL音频API

播放音频的基本流程

  1. 打开音频设备
  2. 设置音频参数
  3. 通过音频回调函数向声卡的缓冲区填充数据
  4. 播放音频
  5. 关闭设备

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a2a9Kbk1-1681661235964)(F:\vivo\记录\音视频开发\图片\播放器\音频播放器简单流程.png)]

注意的两个地方是

  • 声卡向你要数据而不是你主动推给声卡
  • 数据的多少由音频参数决定的。

声卡向你要数据:因为声卡每秒钟播放的数据量的大小它是能计算出来的,也就是通过你的声道数,采样数 等等算出你一秒钟输送的数据量。他会回调一个通知,告诉你要数据了,会调到你写的回调函数里。在这个回调函数中,你要把数据放到一个声卡指定的buff中,他就从buff中取数据。声卡的数据缓冲区大小不一样,都是有一定限制的,如果一下子推送很多数据,很难处理。还不如我给你要数据。需要多少 让你放多少。

SDL_OpenAudio

用于打开音频设备并开始音频处理。该函数有以下原型:

int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)

该函数需要传入两个参数,分别是期望的音频参数和实际获得的音频参数。其中,desired 是指定期望的音频参数,obtained 是实际获得的音频参数,

函数的返回值是一个整数类型,为0表示成功,-1表示失败。如果返回值为-1,可以调用SDL_GetError()函数获取错误信息。

在调用 SDL_OpenAudio 函数时,SDL 会尝试打开符合要求的音频设备,并创建一个音频流。

SDL_OpenAudioDevice

SDL_OpenAudioDevice 函数是用来打开 SDL 音频设备的函数,其原型如下:

SDL_AudioDeviceID SDL_OpenAudioDevice(
    						const char* device, 
    						int iscapture, 
    						const SDL_AudioSpec* desired, 
    						SDL_AudioSpec* obtained, 
    						int allowed_changes)

参数说明:

  • device:要打开的音频设备的名称,可以为 NULL,表示打开默认的音频设备。
  • iscapture:表示是否为录音设备。当其为 0 时,表示打开播放设备;当其为 1 时,表示打开录音设备。
  • desired:期望的音频格式和采样率等信息。如果为 NULL,则表示使用默认的音频格式和采样率等信息。
  • obtained:实际得到的音频格式和采样率等信息。如果为 NULL,则表示不需要获取实际得到的信息。
  • allowed_changes:允许的音频格式和采样率等信息的改变量。如果为 0,则表示不允许任何改变;如果为 -1,则表示允许任何改变;如果为正整数,则表示允许指定数量的改变。

返回值为音频设备的 ID,表示打开音频设备的结果。如果返回 0,则表示打开音频设备失败。

多线程环境下使用这个函数打开音频设备

SDL_CloseAudio

SDL_CloseAudio 是 SDL 库中用于关闭音频设备的函数。在使用 SDL_OpenAudio 打开音频设备后,当不再需要使用音频设备时,应用程序可以调用 SDL_CloseAudio 函数来关闭音频设备。该函数原型如下:

void SDL_CloseAudio(void);

如果需要在程序结束时确保已经关闭所有 SDL 所使用的音频设备,可以在程序退出前调用 SDL_CloseAudio 函数。

需要注意的是,当调用 SDL_CloseAudio 函数时,SDL 库会等待音频播放完成并清空音频缓冲区,然后关闭音频设备。因此,在调用 SDL_CloseAudio 函数之后,应用程序需要等待一段时间,直到音频缓冲区中的数据被播放完毕,然后才能退出程序。例如,可以在退出前使用 SDL_Delay 函数等待一段时间,确保所有的音频数据都已经被播放完毕。

SDL_CloseAudioDevice

SDL_CloseAudioDevice 函数是用来关闭 SDL 音频设备的函数,其原型如下:

void SDL_CloseAudioDevice(SDL_AudioDeviceID dev);

参数说明:

  • dev:音频设备的 ID,表示要关闭的音频设备。

在使用完音频设备后,需要调用 SDL_CloseAudioDevice 函数来关闭音频设备。关闭音频设备后,SDL 就不再调用回调函数来获取音频数据,并且音频设备的缓冲区也会被清空。

需要注意的是,在调用 SDL_CloseAudioDevice 函数之前,应该先使用 SDL_PauseAudioDevice 函数暂停音频设备,并将音频设备的缓冲区中的音频数据清空。否则,如果音频设备的缓冲区中还有未播放的音频数据,那么这些音频数据就会被丢弃,从而导致数据丢失。

另外,需要注意的是,当调用 SDL_CloseAudioDevice 函数关闭音频设备时,如果音频设备的缓冲区中还有未播放的音频数据,那么这些音频数据也会被丢弃。因此,在关闭音频设备之前,应该先等待音频设备播放完所有的音频数据,或者使用 SDL_Delay 函数延迟一段时间,以确保所有的音频数据都被播放完毕。

SDL_PauseAudio

SDL_PauseAudio 是SDL库中提供的一个函数,用于暂停或继续音频播放。该函数的原型如下:

void SDL_PauseAudio(int pause_on);

其中,参数 pause_on 是一个整数,表示是否要暂停音频播放。若值为 1,则暂停播放(暂停音频设备输出流),若值为 0,则继续播放(才可以不断地从缓冲区中取出音频数据进行输)

在使用 SDL_OpenAudio 函数打开音频设备之后,应用程序可以通过调用 SDL_PauseAudio 函数来暂停或继续音频播放。当暂停音频播放时,音频设备会停止向缓冲区填充数据,并在接收到下一次 SDL_PauseAudio 函数的调用时恢复播放。若参数 pause_on 为 0,则音频缓冲区中的数据将不会被暂停,在恢复播放时,它将继续从最后一个位置开始播放。

举个例子,假如我们的应用程序需要播放一段音频,在音频播放时,用户按下了暂停按钮,那么我们可以调用 SDL_PauseAudio(1) 函数来暂停音频播放;当用户点击继续按钮时,我们就可以调用 SDL_PauseAudio(0) 函数来恢复音频播放。这样就可以实现对音频播放的暂停和继续控制。

SDL_PauseAudioDevice

SDL_PauseAudioDevice 函数是用来启动或暂停 SDL 音频设备的函数,其原型如下:

void SDL_PauseAudioDevice(SDL_AudioDeviceID dev, int pause_on);

参数说明:

  • dev:音频设备的 ID,表示要启动或暂停的音频设备。
  • pause_on:表示是否暂停音频设备。当其为 0 时,表示启动音频设备;当其为 1 时,表示暂停音频设备。

在使用 SDL_OpenAudioDevice 函数打开音频设备后,需要使用 SDL_PauseAudioDevice 函数来启动或暂停音频设备。当启动音频设备时,SDL 就会开始调用回调函数来获取音频数据,并将其写入音频设备的缓冲区中。当暂停音频设备时,SDL 就不再调用回调函数,音频设备的缓冲区也不会被写入音频数据。

需要注意的是,当使用 SDL_OpenAudioDevice 函数打开音频设备后,音频设备默认是暂停状态的,需要使用 SDL_PauseAudioDevice 函数来启动音频设备。如果不调用 SDL_PauseAudioDevice 函数来启动音频设备,那么音频设备就不会播放任何音频数据。

另外,需要注意的是,当使用 SDL_PauseAudioDevice 函数暂停音频设备时,如果音频设备的缓冲区中还有未播放的音频数据,那么这些音频数据就会被丢弃。因此,在暂停音频设备之前,应该先将音频设备的缓冲区中的音频数据清空,以免造成数据丢失。

SDL_MixAudio

SDL_MixAudio函数是SDL库中的一个音频处理函数**,主要用于将两个音频缓冲区的数据混合到一起**。(可以理解将一个缓冲区中的数据拷贝到声卡要读取数据的那个缓冲区中去)。函数的定义如下:

void SDL_MixAudio(uint8_t *dst, const uint8_t *src, uint32_t len, int volume);

其中,参数dst表示目标缓冲区的指针,用于存储混合后的音频数据;参数src表示源缓冲区的指针,用于获取需要混合的音频数据;参数len表示需要处理的数据长度,以字节为单位;参数volume表示混合后的音量大小。

SDL_MixAudio的主要作用是将两个缓冲区中的音频数据进行混合,可以实现多个声音来源的混音,达到更好的音效效果。在具体实现中,SDL_MixAudio会按照指定的音量大小,将源缓冲区中的数据和目标缓冲区中的数据进行混合,并将混合结果存储到目标缓冲区中

需要注意的是,SDL_MixAudio操作的两个缓冲区的音频数据格式必须一致,包括采样率、声道数以及数据类型等方面。此外,混合后的音量大小也需要根据具体应用场景进行合理的设置,避免音频数据质量降低或者输出音量过大导致系统无法承受。

音频回调函数

SDL音频回调函数是一种特殊的回调函数,用于向SDL音频设备填充音频数据并实现音频播放。它是用于处理音频流的核心机制,所有音频设备都需要使用此回调函数来填充音频数据并输出到音频设备。

SDL音频回调函数原型如下:

void (*SDL_AudioCallback)(void *userdata, Uint8 *stream, int len);

参数说明:

  • userdata:回调函数的用户数据指针,用于传递额外的参数给回调函数。
  • stream:一个指向缓冲区的指针,用于给音频设备填充音频数据。
  • len:需要填充的数据长度(单位:字节)。

回调函数的机制是:当播放设备需要音频数据时,SDL将调用注册的回调函数,向其传递缓冲区指针和需要填充的数据长度。回调函数需要在接收到这些数据后,快速将其填充到缓冲区中,并返回控制权给SDL音频系统,以便它能够将填充好的音频数据输出到相应的音频设备。

具体来说,回调函数需要执行以下任务:

  1. 从“userdata指针”中读取任何需要的数据。
  2. 计算要向缓冲区中写入的数据量,它通常应该不大于len。
  3. 将音频数据写入缓冲区中。如果数据不够,应该填充“沉默”数据以代替缺失的数据。
  4. 返回控制权给SDL音频系统。

在SDL中,回调函数的限制和要求比较严格。回调函数必须从一个特殊的线程中调用,通常是SDL音频线程。此外,回调函数应该尽量避免长时间的计算或阻塞操作,以便及时响应SDL音频系统的请求。

SDL_CreateMutex

SDL_CreateMutex是SDL库中创建互斥锁的函数

函数原型如下:

SDL_mutex* SDL_CreateMutex(void);

函数返回一个SDL_mutex类型的指针,该指针可以用于访问互斥锁。如果创建互斥锁失败,则返回NULL。

例如,创建一个互斥锁,可以使用以下代码:

SDL_mutex* mutex = SDL_CreateMutex();
if (mutex == NULL) {
    
    
    // 创建互斥锁失败
} else {
    
    
    // 使用互斥锁
    // ...
    // 销毁互斥锁
    SDL_DestroyMutex(mutex);
}

在使用完毕后,需要调用SDL_DestroyMutex()函数来销毁互斥锁对象。

SDL_DestroyMutex

SDL_DestroyMutex是SDL库中销毁互斥锁的函数

函数原型如下:

void SDL_DestroyMutex(SDL_mutex* mutex);

函数参数是一个SDL_mutex类型的指针,该指针指向要销毁的互斥锁。销毁互斥锁之前,应该确保没有任何线程正在使用该互斥锁。

其他API

SDL_Delay

DL_Delay是SDL库中的一个函数,用于让程序暂停一段时间。该函数的原型如下:

void SDL_Delay(Uint32 ms);

其中,ms参数表示需要让程序暂停的时间,以毫秒为单位。例如,如果参数为1000,就表示需要让程序暂停1秒钟。函数返回时,程序将恢复运行。

SDL_memset

SDL_memset函数用于将一块内存中的每个字节都设置为指定的值。函数的定义如下:

void *SDL_memset(void *dst, int value, size_t len);

其中,参数dst是指向需要设置的内存块的指针;参数value表示用来设置内存块中每个字节的值,通常为0或者255;参数len表示内存块的大小,以字节为单位。

SDL相关结构体

SDL_Rect

SDL_Rect 是 SDL2 中定义矩形区域的结构体,通常用于定义窗口中的矩形区域SDL_Rect 结构体定义如下:

typedef struct SDL_Rect
{
    
    
    int x, y;
    int w, h;
} SDL_Rect;

其中,xy 表示矩形的左上角坐标,wh 表示矩形的宽和高。可以通过它们来描述一个矩形区域,如下图所示:

在游戏编程中,我们通常会使用 SDL_Rect 来表示游戏对象的位置和大小。例如,可以定义一个 SDL_Rect 结构体表示玩家角色的矩形区域,如下所示:

SDL_Rect playerRect = {
    
    0, 0, 50, 50};

上面的定义表示玩家角色的矩形区域,左上角坐标为 (0, 0),矩形的宽和高都为 50。

SDL_Texture

SDL_Texture 是一个用于存储像素数据的结构体类型它表示一个纹理对象(texture)。纹理对象是一个在 GPU 内存中的预渲染的图像,可以用于快速渲染。

我们通常将一个位图(bitmap)或者一张图片加载到内存中,并将其创建为一个纹理对象。然后,我们可以使用 SDL_RenderCopy 函数将该纹理对象绘制到渲染目标上,并在需要时进行透明度混合(alpha blending)、裁剪(clipping)等处理。

SDL_Texture 中包含了很多纹理对象所需的信息,包括:

  • wh:表示纹理的宽度和高度,即像素数目。
  • access:表示纹理的访问权限,在使用该纹理对象时,需要先调用 SDL_QueryTexture 函数来获取该访问权限。比较常用的权限有 SDL_TEXTUREACCESS_STATIC(静态访问,只能读取)和 SDL_TEXTUREACCESS_STREAMING(流式访问,可以读写)。
  • format:表示纹理的像素格式,比如 RGBA、BGRA、RGB 等。
  • id:用于标识该纹理对象的一个唯一的非零整数 ID。
  • renderer:指向该纹理对象对应的渲染器(SDL_Renderer 类型)的指针。

SDL_Window

SDL_Window代表的是窗口的逻辑概念,它是存放在主内存中的一个对象。所以当我们调用SDL API 创建窗口后,它并不会被显示出来。

SDL_Surface

SDL 渲染的工作原理。即在SDL_Render对象中有一个视频缓冲区,该缓冲区我们称之为SDL_Surface,它是按照像素存放图像的。我们一般把真彩色的像素称为RGB24数据。也就是说,每一个像素由24位组成,每8位代表一种颜色,像素的最终颜色是由RGB三种颜色混合而成的。

SDL_Texture

SDL中所说的纹理对象就是它。

SDL_Texture 与SDL_Surface相似,也是一种缓冲区。只不过它存放的不是真正的像素数据,而是存放的图像的描述信息。这些描述信息通过OpenGL、D3D 或 Metal等技术操作GPU,从而绘制出与SDL_Surface一样的图形,且效率更高(因为它是GPU硬件计算的)。

SDL_Render

SDL_Render 是渲染器,它也是主存中的一个对象。对Render操作时实际上分为两个阶段:

一、渲染阶段。在该阶段,用户可以画各种图形渲染到SDL_Surface或SDL_Texture 中;

二、显示阶段。参SDL_Texture为数据,通过OpenGL操作GPU,最终将 SDL_Surfce 或SDL_Texture中的数据输出到显示器上。

SDL_AudioSpec

SDL_AudioSpec是SDL中用于描述音频规格的结构体。它包含了一系列参数,用于控制SDL如何处理音频数据。该结构体的定义如下:

typedef struct SDL_AudioSpec {
    
    
    int freq;                   // 采样率
    Uint16 format;              // 采样格式
    Uint8  channels;            // 声道数
    Uint8  silence;             // 静音值,用于表示需要填充到缓冲区中的静音值。
    Uint16 samples;             // 缓冲区中的采样数
    Uint16 padding;             // 对齐位。在有些系统上,需要严格对齐缓冲区指针
    Uint32 size;                // 缓冲区大小,单位是字节
    void (*callback)(void *userdata, Uint8 *stream, int len);  // 回调函数
    void *userdata;             // 回调函数参数
} SDL_AudioSpec;

参数说明:

  • freq:采样率,表示每秒钟采样的次数。
  • format:采样格式,表示每个采样点所占用的位数和正负号等信息。比如SDL支持的格式包括:S8、S16LSB、S16MSB、U16LSB、U16MSB、S32LSB、S32MSB等。
  • channels:声道数,表示采样的声道数目,可以是双声道(2)或单声道(1)等。在SDL中,支持1到65535个声道。一般情况下,双声道比单声道相对更具有立体感和逼真感。
  • silence:静音值,用于表示需要填充到缓冲区中的静音值。
  • samples:缓冲区中的采样数,表示一个缓冲区可以容纳的采样数目。
  • padding:对齐位,这个变量是用来设置缓冲区指针需要按哪个值进行对齐的。不同系统的要求可能不同。
  • size:缓冲区大小,单位是字节。
  • callback:回调函数,用于填充缓冲区,SDL将会自动调用此函数。
  • userdata:回调函数的上下文,用于传递额外的参数给回调函数。

SDL_AudioSpec结构体是SDL实现音频处理的核心,使用它可以自定义音频规格并实现音频回调函数。开发者可以通过填写和配置SDL_AudioSpec结构体,实现对音频设备的控制和管理。

SDL_mutex

SDL_mutex,表示互斥锁,是SDL库提供的一种线程同步机制,用于多个线程之间访问共享资源时的互斥和同步。

SDL_mutex结构体定义在SDL_mutex.h头文件中,包含以下成员:

typedef struct SDL_mutex {
    
    
    void *id;           // 同步机制的底层实现句柄,不同平台实现不同
} SDL_mutex;

SDL_Cond

SDL_Cond 类型代表一个条件变量(condition variable),它是一种线程间同步原语,用于实现线程的协调和交互。条件变量允许一个或多个线程等待某个条件满足后再继续执行

参考

猜你喜欢

转载自blog.csdn.net/qq_38056514/article/details/130190866