96 KiB
[TOC]
预备知识
SDL是什么
一个C语言媒体库,可用于音视频播放、游戏制作等媒体层。
环境准备
Ubuntu
前置条件
已安装gcc/g++/make,如果没安装可用下列命令安装
sudo apt install gcc g++ make
再通过以下命令安装SDL开发环境
sudo apt install libsdl2-dev
Makefile
LDLIBS += -lSDL2
main: main.o # 源文件为main.cpp
$(CXX) $^ -o $@ $(LDFLAGS) $(LDLIBS)
.PHONY: run clean
run: main
./$<
clean:
$(RM) main *.o
Windows
SDL官网地址:http://www.libsdl.org/
SDL GitHub地址:https://github.com/libsdl-org
MinGW
编译器 :MinGW(用的w64devkit包gcc/g++/make)
https://github.com/skeeto/w64devkit/releases
代码编辑器: VSCode
构建方式:手动写Makefile编译构建
所以下载的库为这个版本
解压到指定位置之后准备C语言文件main.c(测试用,先不用理解是啥)
#include <stdlib.h>
#include <time.h>
#include <SDL2/SDL.h>
#undef main
#define WIDTH 1000
#define HEIGHT 600
int main()
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
SDL_Log("Init Failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow(
"TestWindow",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT,
SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(win, -1, 0);
SDL_Rect rect = {100, 100, 100, 100};
srand(time(0));
Uint8 r = 255;
Uint8 g = 255;
Uint8 b = 255;
int8_t dx = 8;
int8_t dy = 10;
int x = rect.x + rect.w / 2;
int y = rect.y + rect.h / 2;
SDL_Event event;
while (1)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
SDL_RenderClear(renderer);
rect.x += dx;
x = rect.x + rect.w / 2;
if (rect.x + rect.w >= WIDTH || rect.x <= 0)
{
dx = -dx;
rect.y += dy;
y = rect.y + rect.h / 2;
if (rect.y + rect.h >= HEIGHT || rect.y <= 0)
{
dy = -dy;
}
r = rand() % 256;
g = rand() % 256;
b = rand() % 256;
}
SDL_SetRenderDrawColor(renderer, r, g, b, 255);
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
for (int i = rect.x; i < rect.x + rect.w; i++)
{
for (int j = rect.y; j < rect.y + rect.h; j++)
{
if ((i - x) * (i - x) + (j - y) * (j - y) > rect.w * rect.h / 4)
{
SDL_RenderDrawPoint(renderer, i, j);
}
}
}
SDL_RenderPresent(renderer);
SDL_Delay(10);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
写如下Makefile
Windows版本Makefile
CXXFLAGS += -ID:/CPP/Libs/SDL2-2.26.5/include #改成你电脑上的include路径
# CXXFLAGS += -fexec-charset=GBK -finput-charset=UTF-8
LDFLAGS += -LD:/CPP/Libs/SDL2-2.26.5/lib # 改成你电脑上的lib路径
CXXFLAGS += -std=c++23
# 如果不用特别新的C++特性,上面这行不用写
LDLIBS += -lSDL2
LDLIBS += -mwindows # 用于去除运行时命令行窗口
main.exe: main.o
$(CXX) $^ -o $(basename $@) $(LDFLAGS) $(LDLIBS)
.PHONY: run clean
run: main.exe
$<
clean:
$(RM) *.exe *.o
完成之后用下列命令编译运行,正常即可
make run
Visual Studio
如果是用其他IDE,则需要自行配置SDL的头文件和库文件引用位置。例如Visual Studio,则需要下载SDL2-devel-2.28.2-VC.zip这个版本的库文件,解压到指定位置后再进行配置。
新建一个Visual Studio的项目,添加main.c文件,内容如下:
#include <stdlib.h>
#include <time.h>
#include <SDL.h>
#undef main
#define WIDTH 1000
#define HEIGHT 600
int main()
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
SDL_Log("Init Failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow(
"TestWindow",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT,
SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(win, -1, 0);
SDL_Rect rect = {100, 100, 100, 100};
srand(time(0));
Uint8 r = 255;
Uint8 g = 255;
Uint8 b = 255;
int8_t dx = 8;
int8_t dy = 10;
int x = rect.x + rect.w / 2;
int y = rect.y + rect.h / 2;
SDL_Event event;
while (1)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
SDL_RenderClear(renderer);
rect.x += dx;
x = rect.x + rect.w / 2;
if (rect.x + rect.w >= WIDTH || rect.x <= 0)
{
dx = -dx;
rect.y += dy;
y = rect.y + rect.h / 2;
if (rect.y + rect.h >= HEIGHT || rect.y <= 0)
{
dy = -dy;
}
r = rand() % 256;
g = rand() % 256;
b = rand() % 256;
}
SDL_SetRenderDrawColor(renderer, r, g, b, 255);
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
for (int i = rect.x; i < rect.x + rect.w; i++)
{
for (int j = rect.y; j < rect.y + rect.h; j++)
{
if ((i - x) * (i - x) + (j - y) * (j - y) > rect.w * rect.h / 4)
{
SDL_RenderDrawPoint(renderer, i, j);
}
}
}
SDL_RenderPresent(renderer);
SDL_Delay(10);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
再配置静态库引用位置,头文件引用位置。最后编译运行测试,如果正常输出信息,则配置正确。其他IDE也是类似,配置好库文件、头文件即可。
Visual Studio 2022配置SDL2开发环境
-
鼠标右键项目-->属性(Properties)打开属性配置面板)
-
路径配置:
配置(Configuration)选择所有配置(All Configuration),平台(Platform)选择x64(也可以选择Win32,需要与后续配置的库对应上)。点击VC++目录(VC++ Directories)分别配置包含目录(Include Directories)和库目录(Library Directories)
包含目录配置:将解压后的SDL中的include目录添加进来,点击确定(OK)。
库目录配置:将解压后的SDL中的lib\x64(如果选的平台是Win32则选x86)目录添加进来,点击确定(OK)。
-
链接库配置:点击链接器(Linker),编辑添加依赖项(Additional Dependencies)
输入SDL2.lib点击确定。
Windows上动态链接库找不到的解决办法
-
将SDL2.dll文件复制到C:\Windows\System32目录下
-
将SDL2.dll所在的目录添加到环境变量
-
将SDL2.dll复制到当前项目生成的.exe文件同级目录
SDL基础应用示例
SDL环境初始化与退出
每次使用SDL都需要进行初始化,使用结束之后需要退出。用到的函数为
初始化与退出
// 初始化
int SDL_Init(Uint32 flags);
// 退出
void SDL_Quit(void);
初始化成功则返回0,失败则返回一个负数。
flags的取值见下表宏定义
例如
使用SDL的C语言文件结构一般如下:
#include <SDL2/SDL.h>
#undef main // 加上这句防止一些奇怪的报错
int main()
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
// 一些操作
// ....
SDL_Quit();
return 0;
}
窗口显示
窗口创建与销毁函数
// 创建函数,成功则返回窗口指针,失败则返回NULL
SDL_Window * SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags);
// 销毁
void SDL_DestroyWindow(SDL_Window * window);
| 参数 | 含义 |
|---|---|
| title | 窗口标题,UTF-8编码 |
| x | 窗口起始位置x坐标 通常为居中SDL_WINDOWPOS_CENTERED或未定义SDL_WINDOWPOS_UNDEFINED |
| y | 窗口起始位置y坐标 通常为居中SDL_WINDOWPOS_CENTERED或未定义SDL_WINDOWPOS_UNDEFINED |
| w | 窗口宽度 |
| h | 窗口高度 |
| flags | 窗口显示标志,可以是0,或者是多个其他标志组合 |
| window | 由SDL_CreateWindow创建返回的窗口指针 |
flags常用可取值(定义在SDL_video.h中),多个值时用|连接
延迟(阻塞)函数
void SDL_Delay(Uint32 ms);
让程序暂停指定的时间,单位为毫秒
完整窗口显示示例
#include <SDL2/SDL.h>
#undef main
int main()
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Window *win = SDL_CreateWindow(
"Hello SDL",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
600, 400,
SDL_WINDOW_SHOWN);
SDL_Delay(5000);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
事件循环
直接用SDL_Delay阻塞程序的话无法响应事件,所以需要加入事件循环进行事件监听。通常做法是把事件循环单独写到一个函数当中,此时SDL程序结构如下:
#include <SDL2/SDL.h>
#define WIDTH 640
#define HEIGHT 480
void event_loop()
{
SDL_Event event;
while (1)
{
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
return;
default:
break;
}
}
}
}
#undef main
int main()
{
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0)
{
SDL_Log("SDL_Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *window = SDL_CreateWindow(
"SDLWindow",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT,
SDL_WINDOW_SHOWN);
if (NULL == window)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
event_loop();
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
结构体SDL_Event
定义于文件 SDL_Events.h中,以下为一些常用成员,如需了解更多请到SDL_Events.h文件中查看
typedef union SDL_Event
{
Uint32 type; // 事件类型,见下
SDL_CommonEvent common; /**< Common event data */
SDL_DisplayEvent display; /**< Display event data */
SDL_WindowEvent window; /**< Window event data */
SDL_KeyboardEvent key; /**< Keyboard event data */
SDL_TextEditingEvent edit; /**< Text editing event data */
SDL_TextEditingExtEvent editExt; /**< Extended text editing event data */
SDL_TextInputEvent text; /**< Text input event data */
SDL_MouseMotionEvent motion; /**< Mouse motion event data */
SDL_MouseButtonEvent button; /**< Mouse button event data */
SDL_MouseWheelEvent wheel; /**< Mouse wheel event data */
SDL_AudioDeviceEvent adevice; /**< Audio device event data */
SDL_SensorEvent sensor; /**< Sensor event data */
SDL_QuitEvent quit; /**< Quit request event data */
SDL_UserEvent user; /**< Custom event data */
SDL_SysWMEvent syswm; /**< System dependent window event data */
SDL_TouchFingerEvent tfinger; /**< Touch finger event data */
SDL_MultiGestureEvent mgesture; /**< Gesture event data */
SDL_DollarGestureEvent dgesture; /**< Gesture event data */
SDL_DropEvent drop; /**< Drag and drop event data */
// ....更多内容请查阅SDL_Events.h文件
} SDL_Event;
枚举类型SDL_EventType
事件类型,定义于文件 SDL_Events.h中,以下为一些常用成员,如需了解更多请查阅 SDL_Events.h文件
typedef enum
{
SDL_QUIT = 0x100, // 用户请求 退出
/* 键盘事件 */
SDL_KEYDOWN = 0x300, // 键盘按下
SDL_KEYUP, // 键盘弹起
SDL_TEXTEDITING, //
SDL_TEXTINPUT, // 文字输入
/* 鼠标事件 */
SDL_MOUSEMOTION = 0x400, // 鼠标运动
SDL_MOUSEBUTTONDOWN, // 鼠标键按下
SDL_MOUSEBUTTONUP, // 鼠标键松开
SDL_MOUSEWHEEL, // 鼠标滚轮滚动
// .... 更多事件类型请到SDL_Events.h文件查看
} SDL_EventType;
事件检测函数
int SDL_PollEvent(SDL_Event * event)
检测是否有等待处理的事件。如果队列中有事件,则把里面的第一个事件从事件队列中移除,保存到event这个指针中,并返回1。如果已经没有事件,则返回0。
event用于接收事件队列中下一事件的指针,如果没有等待的事件则用NULL填充。
图形绘制
在屏幕上绘制一个矩形需要用到如下三个函数
// 获取与对应window关联的SDL surface,失败则返回NULL
SDL_Surface * SDL_GetWindowSurface(SDL_Window * window);
// 在SDL surface上画一个矩形区域,成功返回0, 失败返回负数
int SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color);
// 将surface的内容更新到屏幕上,成功返回0, 失败返回负数
int SDL_UpdateWindowSurface(SDL_Window * window)
color为4个字节无符号整数,为4通道颜色值ARGB,其中第一个字节为Alpha通道,即透明度通道;R为红色分量通道;G为绿色分量通道;B为蓝色分量通道。通常用十六进制表示,例如0xff00aa8c。用这种方式绘制图形时,透明通道是不生效的,所以颜色值可以只写三个字节RGB分量,例如0xff00bb。
如果不习惯将颜色值写成一整个十六进制数值,可以将各个通道值分开写,则需要用到如下函数进行转换:
// 将R,G, B三个通道分量转换为一个整数值。三个分量取值范围均为0~255
Uint32 SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b);
// 将R, G, B, A四个通道分量转为一个整数值。四个分量取值范围均为0~255
Uint32 SDLCALL SDL_MapRGBA(const SDL_PixelFormat * format,
Uint8 r, Uint8 g, Uint8 b,
Uint8 a);
SDL_PixelFormat由以下方式获得与释放
SDL_PixelFormat * format = SDL_AllocFormat(SDL_PIXELFORMAT_BGRA32);
SDL_FreeFormat(format);
SDL_AllocFormat的参数为枚举类型SDL_PixelFormatEnum,定义在SDL_pixels.h里,常用的有:
- 三通道:SDL_PIXELFORMAT_RGB24,SDL_PIXELFORMAT_BGR24
- 四通道:SDL_PIXELFORMAT_ARGB32,SDL_PIXELFORMAT_BGRA32
小端存储的用BGR这个顺序的,大端存储的用RGB这个顺序的,如果无法判断用哪个,可每个顺序试一下看是否能达到想要的效果即可。
完整颜色转换示例:
SDL_PixelFormat * format = SDL_AllocFormat(SDL_PIXELFORMAT_BGR24);
Uint32 color = SDL_MapRGB(format, 255, 0, 111));
SDL_FreeFormat(format);
SDL_Rect
在屏幕上绘制矩形
#include <SDL2/SDL.h>
#define W 1200
#define H 800
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 在窗口上绘制一个矩形
// 1. 获取与窗口关联的Surface
SDL_Surface *surf = SDL_GetWindowSurface(win);
if (NULL == surf)
{
SDL_Log("SDL_GetWindowSurface failed: %s", SDL_GetError());
return -1;
}
// 2. 定义一个区域
SDL_Rect rect = {200, 200, 50, 50};
// 3. 在Surface上进行绘制
// SDL_FillRect(surf, &rect, SDL_MapRGB(surf->format, 0, 255, 0));
SDL_FillRect(surf, &rect, 0x00ff00);
// 4. 将绘制的内容更新到屏幕上
SDL_UpdateWindowSurface(win);
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
SDL_FillRect(surf, &rect, 0x000000);
rect.x += 2;
SDL_FillRect(surf, &rect, 0x00ff00);
SDL_UpdateWindowSurface(win);
SDL_Delay(10);
}
// 4. 释放Surface
SDL_FreeSurface(surf);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
图片显示
SDL核心库只支持BMP图片的操作。如需操作更多格式的图片,需要SDL2_image库,添加与使用方式与SDL核心库一样。头文件为#include <SDL2/SDL_image.h>,库文件为SDL2_image。这里为了简便不再引入SDL2_image库,直接使用BMP图片进行操作。
#include <SDL2/SDL.h>
#define W 1200
#define H 800
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 显示BMP图片
// 1. 获取与窗口关联的Surface
SDL_Surface *surf = SDL_GetWindowSurface(win);
if (NULL == surf)
{
SDL_Log("SDL_GetWindowSurface failed: %s", SDL_GetError());
return -1;
}
// 2. 导入BMP图片
SDL_Surface *img_surf = SDL_LoadBMP("8.bmp");
if (NULL == img_surf)
{
SDL_Log("SDL_LoadBMP failed: %s", SDL_GetError());
return -1;
}
// 3. 将图片Surface复制到窗口Surface上
SDL_BlitSurface(img_surf, NULL, surf, NULL);
// 4. 将绘制的内容更新到屏幕上
SDL_UpdateWindowSurface(win);
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
}
// 4. 释放Surface
SDL_FreeSurface(img_surf);
SDL_FreeSurface(surf);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
像素点操作
修改像素点的颜色值
#include <SDL2/SDL.h>
#define W 600
#define H 400
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 操作像素点
// 1. 获取与窗口关联的Surface
SDL_Surface *surf = SDL_GetWindowSurface(win);
if (NULL == surf)
{
SDL_Log("SDL_GetWindowSurface failed: %s", SDL_GetError());
return -1;
}
// 2. 修改像素点颜色值
Uint32 *px = (Uint32 *)surf->pixels;
px[20000] = 0xffffff;
// 3. 将绘制的内容更新到屏幕上
SDL_UpdateWindowSurface(win);
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
}
// 4. 释放Surface
SDL_FreeSurface(surf);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
随机像素点显示照片
#include <SDL2/SDL.h>
#include <random>
#undef main
void event_loop()
{
SDL_Event event;
while (1)
{
if (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
return;
default:
break;
}
}
}
}
typedef struct tagARGB {
Uint8 b;
Uint8 g;
Uint8 r;
Uint8 a;
} ARGB;
typedef struct tagRGB {
Uint8 b;
Uint8 g;
Uint8 r;
} RGB;
void swap_value(Uint32 *ptr1, Uint32 *ptr2)
{
Uint32 tmp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = tmp;
}
void shuffle_array(Uint32 arr[], Uint32 count)
{
std::random_device rdv;
std::default_random_engine rdn(rdv());
std::uniform_int_distribution<> distrib(0, count);
Uint32 j = 0;
for (Uint32 i = 0; i < count; i++)
{
j = distrib(rdn);
if (i != j)
{
swap_value(&arr[i], &arr[j]);
}
}
}
int main()
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
SDL_Surface *bmpimg = SDL_LoadBMP("1684826393041.bmp");
SDL_Window *win = SDL_CreateWindow(
"像素显示图片",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
bmpimg->w, bmpimg->h,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
SDL_Surface *surf = SDL_GetWindowSurface(win);
ARGB *px = (ARGB *)surf->pixels;
Uint32 index = 0;
Uint32 max_num = surf->w * surf->h;
Uint32 *index_arr = (Uint32 *)malloc(max_num * sizeof(Uint32));
for (Uint32 i = 0; i < max_num; i++)
{
index_arr[i] = i;
}
shuffle_array(index_arr, max_num);
for (int i = max_num - 1; i >= 0; i--)
{
px[index_arr[i]].a = 255;
px[index_arr[i]].r = ((RGB *)bmpimg->pixels)[index_arr[i]].r;
px[index_arr[i]].g = ((RGB *)bmpimg->pixels)[index_arr[i]].g;
px[index_arr[i]].b = ((RGB *)bmpimg->pixels)[index_arr[i]].b;
if (i % 200 == 0)
{
SDL_UpdateWindowSurface(win);
SDL_Delay(1);
}
}
SDL_UpdateWindowSurface(win);
event_loop();
free(index_arr);
SDL_FreeSurface(surf);
SDL_DestroyWindow(win);
SDL_FreeSurface(bmpimg);
SDL_Quit();
return 0;
}
绘制玫瑰
#include <math.h>
#include <SDL2/SDL.h>
#undef main
// 定义全局变量
int rosesize = 500;
int h = -250;
// 定义结构体
struct DOT
{
double x;
double y;
double z;
double r; // 红色
double g; // 绿色
// b(蓝色) 通过 r 计算
};
// 计算点
bool calc(double a, double b, double c, DOT &d)
{
double j, n, o, w, z;
if(c > 60) // 花柄
{
d.x = sin(a * 7) * (13 + 5 / (0.2 + pow(b * 4, 4))) - sin(b) * 50;
d.y = b * rosesize + 50;
d.z = 625 + cos(a * 7) * (13 + 5 / (0.2 + pow(b * 4, 4))) + b * 400;
d.r = a * 1 - b / 2;
d.g = a;
return true;
}
double A = a * 2 - 1;
double B = b * 2 - 1;
if(A * A + B * B < 1)
{
if(c > 37) // 叶
{
j = (int(c) & 1);
n = j ? 6 : 4;
o = 0.5 / (a + 0.01) + cos(b * 125) * 3 - a * 300;
w = b * h;
d.x = o * cos(n) + w * sin(n) + j * 610 - 390;
d.y = o * sin(n) - w * cos(n) + 550 - j * 350;
d.z = 1180 + cos(B + A) * 99 - j * 300;
d.r = 0.4 - a * 0.1 + pow(1 - B * B, -h * 6) * 0.15 - a * b * 0.4 + cos(a + b) / 5 + pow(cos((o * (a + 1) + (B > 0 ? w : -w)) / 25), 30) * 0.1 * (1 - B * B);
d.g = o / 1000 + 0.7 - o * w * 0.000003;
return true;
}
if(c > 32) // 花萼
{
c = c * 1.16 - 0.15;
o = a * 45 - 20;
w = b * b * h;
z = o * sin(c) + w * cos(c) + 620;
d.x = o * cos(c) - w * sin(c);
d.y = 28 + cos(B * 0.5) * 99 - b * b * b * 60 - z / 2 - h;
d.z = z;
d.r = (b * b * 0.3 + pow((1 - (A * A)), 7) * 0.15 + 0.3) * b;
d.g = b * 0.7;
return true;
}
// 花
o = A * (2 - b) * (80 - c * 2);
w = 99 - cos(A) * 120 - cos(b) * (-h - c * 4.9) + cos(pow(1 - b, 7)) * 50 + c * 2;
z = o * sin(c) + w * cos(c) + 700;
d.x = o * cos(c) - w * sin(c);
d.y = B * 99 - cos(pow(b, 7)) * 50 - c / 3 - z / 1.35 + 450;
d.z = z;
d.r = (1 - b / 1.2) * 0.9 + a * 0.1;
d.g = pow((1 - b), 20) / 4 + 0.05;
return true;
}
return false;
}
int main()
{
short *zBuffer;
int x, y, z, zBufferIndex;
DOT dot;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
SDL_Log("Init Failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow(
"花花",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480,
SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("Window create failed: %s", SDL_GetError());
return -1;
}
SDL_Surface *win_surface = SDL_GetWindowSurface(win);
SDL_Rect rect = {0, 0, win_surface->w, win_surface->h};
SDL_FillRect(win_surface, &rect, 0xffffffff);
SDL_UpdateWindowSurface(win);
// 初始化 z-buffer
zBuffer = new short[rosesize * rosesize];
memset(zBuffer, 0, sizeof(short) * rosesize * rosesize);
SDL_Event event;
while (1)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
for(int i = 0; i < 1000; i++)
{
if(calc(double(rand()) / RAND_MAX, double(rand()) / RAND_MAX, rand() % 46 / 0.74, dot))
{
z = int(dot.z + 0.5);
x = int(dot.x * rosesize / z - h + 0.5);
y = int(dot.y * rosesize / z - h + 0.5);
if (y >= rosesize) continue;
zBufferIndex = y * rosesize + x;
if(!zBuffer[zBufferIndex] || zBuffer[zBufferIndex] > z)
{
zBuffer[zBufferIndex] = z;
// 画点
int r = ~int((dot.r * h)); if (r < 0) r = 0; if (r > 255) r = 255;
int g = ~int((dot.g * h)); if (g < 0) g = 0; if (g > 255) g = 255;
int b = ~int((dot.r * dot.r * -80)); if (b < 0) b = 0; if (b > 255) b = 255;
int index = (x + 50) + (y - 20) * win_surface->w;
((Uint32 *)win_surface->pixels)[index] = SDL_MapRGB(win_surface->format, r, g, b);
}
}
}
SDL_UpdateWindowSurface(win);
SDL_Delay(1);
}
delete []zBuffer;
SDL_FreeSurface(win_surface);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
渲染
渲染器创建与清屏
#include <SDL2/SDL.h>
#define W 800
#define H 600
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器与清屏
// 1. 创建渲染器
SDL_Renderer *rdr = SDL_CreateRenderer(win, -1, 0);
// 2. 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
// 3. 清除屏幕
SDL_RenderClear(rdr);
// 4. 渲染呈现
SDL_RenderPresent(rdr);
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
}
// 5. 销毁渲染器
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
绘制点、线
#include <deque>
#include <SDL2/SDL.h>
#define W 800
#define H 600
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器与清屏
SDL_Renderer *rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
// 清除屏幕
SDL_RenderClear(rdr);
// 渲染点、线
SDL_SetRenderDrawColor(rdr, 0, 0, 0, 255);
SDL_RenderDrawPoint(rdr, 200, 200);
for (int i = 200; i < 300; i+=5)
{
SDL_RenderDrawPoint(rdr, i, 200);
}
SDL_RenderDrawLine(rdr, 0, 0, 200, 250);
SDL_Point pt[5] = {{0, 0}, {100, 100}, {100, 300}, {200, 100}, {250, 190}};
SDL_RenderDrawLines(rdr, pt, 5);
// 渲染呈现
SDL_RenderPresent(rdr);
// 练习:绘制一个19*19的围棋棋盘
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
}
// 销毁渲染器
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
绘制、填充矩形区域
#include <SDL2/SDL.h>
#define W 800
#define H 600
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器与清屏
SDL_Renderer *rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
// 清除屏幕
SDL_RenderClear(rdr);
SDL_SetRenderDrawBlendMode(rdr, SDL_BLENDMODE_BLEND);
// 渲染矩形
SDL_SetRenderDrawColor(rdr, 0, 0, 0, 255);
SDL_Rect rect = {200, 200, 100, 100};
// SDL_RenderDrawRect(rdr, &rect);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
// 练习:思考一下如何实现贪吃蛇一条蛇移动的效果
// 可以借助一下vector/deque等容器
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
// 清除屏幕
// SDL_RenderClear(rdr);
SDL_RenderFillRect(rdr, &rect);
SDL_SetRenderDrawColor(rdr, 0, 0, 0, 255);
rect.x ++;
// SDL_RenderDrawRect(rdr, &rect);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
SDL_Delay(10);
}
// 销毁渲染器
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
图片渲染
#include <SDL2/SDL.h>
#define W 1369
#define H 768
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器与清屏
SDL_Renderer *rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
// 清除屏幕
SDL_RenderClear(rdr);
// 渲染图片
// 1. 导入图片
SDL_Surface *img_surf = SDL_LoadBMP("../SDL/img/2.bmp"); // 1296*864
if (NULL == img_surf)
{
SDL_Log("SDL_LoadBMP failed: %s", SDL_GetError());
return -1;
}
SDL_SetWindowSize(win, img_surf->w, img_surf->h);
// 2. 创建Texture
SDL_Texture *texture = SDL_CreateTextureFromSurface(rdr, img_surf);
if (NULL == texture)
{
SDL_Log("SDL_CreateTextureFromSurface failed: %s", SDL_GetError());
return -1;
}
SDL_Rect rect = {200, 200, 648, 432};
// 3. 复制Texture
SDL_RenderCopy(rdr, texture, NULL, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
}
// 5. 销毁Texture
SDL_DestroyTexture(texture);
SDL_FreeSurface(img_surf);
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
图片缩放、旋转
#include <SDL2/SDL.h>
#define W 1369
#define H 768
#undef main
int main()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
SDL_Window *win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器与清屏
SDL_Renderer *rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
// 清除屏幕
SDL_RenderClear(rdr);
// 渲染图片
// 1. 导入图片
SDL_Surface *img_surf = SDL_LoadBMP("../SDL/img/2.bmp"); // 1296*864
if (NULL == img_surf)
{
SDL_Log("SDL_LoadBMP failed: %s", SDL_GetError());
return -1;
}
SDL_SetWindowSize(win, img_surf->w, img_surf->h);
// 2. 创建Texture
SDL_Texture *texture = SDL_CreateTextureFromSurface(rdr, img_surf);
if (NULL == texture)
{
SDL_Log("SDL_CreateTextureFromSurface failed: %s", SDL_GetError());
return -1;
}
SDL_Rect rect = {200, 200, 648, 432};
SDL_Point pt = {0, 0};
// 3. 复制Texture
SDL_RenderCopyEx(rdr, texture, NULL, &rect, 90, NULL, SDL_FLIP_NONE);
// 渲染呈现
SDL_RenderPresent(rdr);
SDL_Event event;
while (true)
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
break;
}
}
}
// 5. 销毁Texture
SDL_DestroyTexture(texture);
SDL_FreeSurface(img_surf);
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
代码结构整理
#include <SDL2/SDL.h>
#define W 720
#define H 640
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
SDL_Rect rect = {100, 100, 200, 100};
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
int draw()
{
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 100, 100, 100, 100);
// 清除屏幕
SDL_RenderClear(rdr);
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
return 0;
}
void event_loop()
{
SDL_Event event;
while (true)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
return;
default:
break;
}
}
}
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw();
event_loop();
deinit();
return 0;
}
窗口事件
#include <SDL2/SDL.h>
#define W 720
#define H 640
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
SDL_Rect rect = {100, 100, 200, 100};
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
int draw()
{
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 100, 100, 100, 100);
// 清除屏幕
SDL_RenderClear(rdr);
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
return 0;
}
void event_loop()
{
SDL_Event event;
while (true)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
return;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
draw();
}
break;
default:
break;
}
}
}
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw();
event_loop();
deinit();
return 0;
}
鼠标事件
移动
#include <SDL2/SDL.h>
#define W 720
#define H 640
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
SDL_Rect rect = {100, 100, 200, 100};
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
int draw()
{
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 100, 100, 100, 100);
// 清除屏幕
SDL_RenderClear(rdr);
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
return 0;
}
void event_loop()
{
SDL_Event event;
while (true)
{
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
return;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
draw();
}
break;
case SDL_MOUSEMOTION:
SDL_Log("x = %d, y = %d", event.motion.x, event.motion.y);
rect.x = event.motion.x - 100;
rect.y = event.motion.y - 50;
draw();
break;
default:
break;
}
}
}
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw();
event_loop();
deinit();
return 0;
}
按键
#include <SDL2/SDL.h>
#define W 720
#define H 640
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
SDL_Rect rect = {100, 100, 200, 100};
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
int draw()
{
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 100, 100, 100, 100);
// 清除屏幕
SDL_RenderClear(rdr);
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
return 0;
}
void event_loop()
{
SDL_Event event;
while (true)
{
while (SDL_PollEvent(&event))
{
SDL_Point pt;
switch (event.type)
{
case SDL_QUIT:
return;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
draw();
}
break;
case SDL_MOUSEMOTION:
// SDL_Log("x = %d, y = %d", event.motion.x, event.motion.y);
// rect.x = event.motion.x - 100;
// rect.y = event.motion.y - 50;
// draw();
break;
case SDL_MOUSEBUTTONDOWN:
SDL_Log("SDL_MOUSEBUTTONDOWN x = %d, y = %d, button = %d, clicks = %d",
event.button.x, event.button.y, event.button.button, event.button.clicks);
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 200, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
case SDL_MOUSEBUTTONUP:
SDL_Log("SDL_MOUSEBUTTONUP x = %d, y = %d, button = %d, clicks = %d",
event.button.x, event.button.y, event.button.button, event.button.clicks);
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
default:
break;
}
}
}
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw();
event_loop();
deinit();
return 0;
}
键盘事件
#include <SDL2/SDL.h>
#define W 720
#define H 640
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
SDL_Rect rect = {100, 100, 50, 50};
int dx = 1;
int dy = 0;
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
int draw()
{
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 100, 100, 100, 100);
// 清除屏幕
SDL_RenderClear(rdr);
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
return 0;
}
void event_loop()
{
SDL_Event event;
while (true)
{
while (SDL_PollEvent(&event))
{
SDL_Point pt;
switch (event.type)
{
case SDL_QUIT:
return;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
draw();
}
break;
case SDL_MOUSEMOTION:
// SDL_Log("x = %d, y = %d", event.motion.x, event.motion.y);
// rect.x = event.motion.x - 100;
// rect.y = event.motion.y - 50;
// draw();
break;
case SDL_MOUSEBUTTONDOWN:
SDL_Log("SDL_MOUSEBUTTONDOWN x = %d, y = %d, button = %d, clicks = %d",
event.button.x, event.button.y, event.button.button, event.button.clicks);
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 200, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
case SDL_MOUSEBUTTONUP:
SDL_Log("SDL_MOUSEBUTTONUP x = %d, y = %d, button = %d, clicks = %d",
event.button.x, event.button.y, event.button.button, event.button.clicks);
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_UP)
{
SDL_Log("UP");
dy = -1;
dx = 0;
}
if (event.key.keysym.sym == SDLK_DOWN)
{
SDL_Log("DOWN");
dy = 1;
dx = 0;
}
if (event.key.keysym.sym == SDLK_LEFT)
{
SDL_Log("LEFT");
dx = -1;
dy = 0;
}
if (event.key.keysym.sym == SDLK_RIGHT)
{
SDL_Log("RIGHT");
dx = 1;
dy = 0;
}
break;
case SDL_KEYUP:
break;
case SDL_TEXTEDITING:
SDL_Log("Edit %s", event.edit.text);
break;
case SDL_TEXTINPUT:
SDL_Log("Input %s", event.text.text);
break;
default:
break;
}
}
rect.x += dx;
rect.y += dy;
draw();
SDL_Delay(10);
}
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw();
event_loop();
deinit();
return 0;
}
碰撞以及范围检测
播放声音
#include <SDL2/SDL.h>
#define W 1027
#define H 761
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
SDL_Rect rect = {100, 100, 50, 50};
int dx = 1;
int dy = 0;
Uint8 *audio_buf;
Uint32 audio_len;
Uint32 audio_pos = 0;
SDL_AudioDeviceID device_id;
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_CloseAudioDevice(device_id);
SDL_FreeWAV(audio_buf);
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
int draw()
{
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 100, 100, 100, 100);
// 清除屏幕
SDL_RenderClear(rdr);
SDL_Surface *surf = SDL_LoadBMP("10.bmp");
SDL_Texture *texture = SDL_CreateTextureFromSurface(rdr, surf);
SDL_RenderCopy(rdr, texture, NULL, NULL);
// 渲染呈现
SDL_RenderPresent(rdr);
SDL_DestroyTexture(texture);
SDL_FreeSurface(surf);
return 0;
}
void event_loop()
{
SDL_Event event;
while (true)
{
while (SDL_PollEvent(&event))
{
SDL_Point pt;
switch (event.type)
{
case SDL_QUIT:
return;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
draw();
}
break;
case SDL_MOUSEMOTION:
// SDL_Log("x = %d, y = %d", event.motion.x, event.motion.y);
// rect.x = event.motion.x - 100;
// rect.y = event.motion.y - 50;
// draw();
break;
case SDL_MOUSEBUTTONDOWN:
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 200, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
case SDL_MOUSEBUTTONUP:
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_UP)
{
dy = -1;
dx = 0;
}
if (event.key.keysym.sym == SDLK_DOWN)
{
dy = 1;
dx = 0;
}
if (event.key.keysym.sym == SDLK_LEFT)
{
dx = -1;
dy = 0;
}
if (event.key.keysym.sym == SDLK_RIGHT)
{
dx = 1;
dy = 0;
}
break;
case SDL_KEYUP:
break;
case SDL_TEXTEDITING:
break;
case SDL_TEXTINPUT:
break;
default:
break;
}
}
// draw();
SDL_Delay(10);
}
}
void callback(void *userdata, Uint8 * stream, int len)
{
int remain = audio_len - audio_pos;
if (remain > len)
{
SDL_memcpy(stream, audio_buf + audio_pos, len);
audio_pos += len;
}
else
{
SDL_memcpy(stream, audio_buf + audio_pos, remain);
audio_pos = 0;
}
}
void play_wav()
{
SDL_AudioSpec audio_spec;
// 1. 导入WAV文件
SDL_LoadWAV("1.wav", &audio_spec, &audio_buf, &audio_len);
// 2. 定义播放回调函数
audio_spec.userdata = (void *)"这是外部传进来的数据";
audio_spec.callback = callback;
// 3. 打开音频设备
device_id = SDL_OpenAudioDevice(NULL, 0, &audio_spec, NULL, 0);
// 4. 开始播放
SDL_PauseAudioDevice(device_id, 0);
// 5. 释放资源 关闭设备
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw();
play_wav();
event_loop();
deinit();
return 0;
}
动画帧率
#include <SDL2/SDL.h>
#define W 1280
#define H 720
#define FR 25
#define FT 1000 / FR
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
SDL_Rect rect = {100, 100, 50, 50};
int dx = 1;
int dy = 0;
int index = 0;
Uint8 *audio_buf;
Uint32 audio_len;
Uint32 audio_pos = 0;
SDL_AudioDeviceID device_id;
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_FreeWAV(audio_buf);
SDL_CloseAudioDevice(device_id);
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
int draw()
{
// 设置渲染颜色
SDL_SetRenderDrawColor(rdr, 100, 100, 100, 100);
// 清除屏幕
SDL_RenderClear(rdr);
char file[20] = {0};
if (index > 1736)
{
return -1;
}
SDL_snprintf(file, 20, "img/%d.bmp", index++);
SDL_Surface *surf = SDL_LoadBMP(file);
SDL_Texture *texture = SDL_CreateTextureFromSurface(rdr, surf);
SDL_RenderCopy(rdr, texture, NULL, NULL);
// 渲染呈现
SDL_RenderPresent(rdr);
SDL_DestroyTexture(texture);
SDL_FreeSurface(surf);
return 0;
}
void event_loop()
{
SDL_Event event;
Uint64 start, end;
int delay;
while (true)
{
start = SDL_GetTicks64();
while (SDL_PollEvent(&event))
{
SDL_Point pt;
switch (event.type)
{
case SDL_QUIT:
return;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
draw();
}
break;
case SDL_MOUSEMOTION:
// SDL_Log("x = %d, y = %d", event.motion.x, event.motion.y);
// rect.x = event.motion.x - 100;
// rect.y = event.motion.y - 50;
// draw();
break;
case SDL_MOUSEBUTTONDOWN:
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 200, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
case SDL_MOUSEBUTTONUP:
pt = {event.button.x, event.button.y};
if (SDL_PointInRect(&pt, &rect))
{
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 255);
SDL_RenderFillRect(rdr, &rect);
// 渲染呈现
SDL_RenderPresent(rdr);
}
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_UP)
{
dy = -1;
dx = 0;
}
if (event.key.keysym.sym == SDLK_DOWN)
{
dy = 1;
dx = 0;
}
if (event.key.keysym.sym == SDLK_LEFT)
{
dx = -1;
dy = 0;
}
if (event.key.keysym.sym == SDLK_RIGHT)
{
dx = 1;
dy = 0;
}
break;
case SDL_KEYUP:
break;
case SDL_TEXTEDITING:
break;
case SDL_TEXTINPUT:
break;
default:
break;
}
}
draw();
end = SDL_GetTicks64();
delay = FT - (end -start);
if (delay > 0)
{
SDL_Delay(delay);
}
}
}
void callback(void *userdata, Uint8 * stream, int len)
{
int remain = audio_len - audio_pos;
if (remain > len)
{
SDL_memcpy(stream, audio_buf + audio_pos, len);
audio_pos += len;
}
else
{
SDL_memcpy(stream, audio_buf + audio_pos, remain);
audio_pos = 0;
}
}
void play_wav()
{
SDL_AudioSpec audio_spec;
// 1. 导入WAV文件
if (SDL_LoadWAV("2.wav", &audio_spec, &audio_buf, &audio_len) == NULL)
{
SDL_Log("SDL_LoadWAV failed: %s", SDL_GetError());
return;
}
// 2. 定义播放回调函数
audio_spec.callback = callback;
audio_spec.userdata = (void *)"这是外部传进来的数据";
// 3. 打开音频设备
device_id = SDL_OpenAudioDevice(NULL, 0, &audio_spec, NULL, 0);
// 4. 开始播放
SDL_PauseAudioDevice(device_id, 0);
// 5. 释放资源 关闭设备
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw();
play_wav();
event_loop();
deinit();
return 0;
}
其他模块使用
其他模块的使用方式同核心模块一样,下载对应的库文件,将头文件、库文件合并到核心库的安装目录,在配置中添加对应的库即可。
CXXFLAGS += -IC:/Users/YAN/Desktop/SDL/lib/SDL2-devel-2.28.2-mingw/SDL2-2.28.2/x86_64-w64-mingw32/include #改成你电脑上的include路径
# CXXFLAGS += -fexec-charset=GBK -finput-charset=UTF-8
LDFLAGS += -LC:/Users/YAN/Desktop/SDL/lib/SDL2-devel-2.28.2-mingw/SDL2-2.28.2/x86_64-w64-mingw32/lib
CXXFLAGS += -std=c++23
LDLIBS += -lSDL2 -lSDL2_ttf # 链接库时加上对应的模块
LDLIBS += -mwindows
main.exe: main.o
$(CXX) $^ -o $(basename $@) $(LDFLAGS) $(LDLIBS)
.PHONY: run clean
run: main.exe
$<
clean:
$(RM) *.exe *.o
文字模块示例
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#define W 1280
#define H 720
SDL_Window *win = NULL;
SDL_Renderer *rdr = NULL;
int init()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("Init failed: %s", SDL_GetError());
return -1;
}
win = SDL_CreateWindow("Hello", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
W, H, SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN);
if (NULL == win)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
// 创建渲染器
rdr = SDL_CreateRenderer(win, -1, 0);
if (NULL == rdr)
{
SDL_Log("SDL_CreateRenderer failed: %s", SDL_GetError());
return -1;
}
return 0;
}
void deinit()
{
// 销毁
SDL_FreeWAV(audio_buf);
SDL_CloseAudioDevice(device_id);
SDL_DestroyRenderer(rdr);
SDL_DestroyWindow(win);
SDL_Quit();
}
void event_loop()
{
SDL_Event event;
while (true)
{
while (SDL_PollEvent(&event))
{
SDL_Point pt;
switch (event.type)
{
case SDL_QUIT:
return;
default:
break;
}
}
}
}
void draw_text()
{
// 1. 初始化TTF
if (TTF_Init() < 0)
{
SDL_Log("TTF_Init failed: %s", TTF_GetError());
return ;
}
// 2. 打开字体
TTF_Font *font = TTF_OpenFont("C:\\Windows\\Fonts\\simfang.ttf", 48);
if (!font)
{
SDL_Log("TTF_OpenFont failed: %s", TTF_GetError());
return ;
}
// 3. 渲染字体
SDL_Surface *txt_surf = TTF_RenderUTF8_LCD(font, "你好Hello", {255, 255, 255, 50}, {0, 0, 255, 0});
if (!txt_surf)
{
SDL_Log("TTF_RenderText_Solid failed: %s", TTF_GetError());
return ;
}
// 4. 获取与窗口关联的Surface
SDL_Surface *surf = SDL_GetWindowSurface(win);
if (!surf)
{
SDL_Log("SDL_GetWindowSurface failed: %s", SDL_GetError());
return ;
}
// 5. 将字体Surface复制到窗口Surface上
SDL_Rect rect = {500, 300, txt_surf->w, txt_surf->h};
SDL_BlitSurface(txt_surf, NULL, surf, &rect);
// 6. 更新窗口
SDL_UpdateWindowSurface(win);
// 7. 释放与销毁资源
SDL_FreeSurface(surf);
SDL_FreeSurface(txt_surf);
TTF_CloseFont(font);
TTF_Quit();
}
#undef main
int main()
{
if (init() < 0)
{
return -1;
}
draw_text();
event_loop();
deinit();
return 0;
}
关于文字渲染的几种类型:
*_Solid: 使用纯色填充,速度快,文字渲染质量不佳
*_Shaded: 使用纯色填充,添加一定阴影效果
*_Blended: 使用抗锯齿算法高质量渲染
*_LCD: 针对LCD显示器优化渲染
多线程操作
SDL常用函数、结构体、枚举、宏定义
函数
SDL_Init
声明
// SDL.h
int SDL_Init(Uint32 flags);
功能
初始化SDL库(子系统)。
参数
接收参数为宏定义,见下表
| flags取值 | 初始化系统 |
|---|---|
| SDL_INIT_VIDEO | 视频子系统,会自动初始化事件子系统 |
| SDL_INIT_AUDIO | 音频子系统 |
| SDL_INIT_TIMER | 定时器子系统 |
| SDL_INIT_EVENTS | 事件子系统 |
| SDL_INIT_JOYSTICK | 操纵杆子系统,自动初始化事件子系统 |
| SDL_INIT_HAPTIC | 触觉子系统 |
| SDL_INIT_GAMECONTROLLER | 控制子系统,自动初始化操纵杆子系统 |
| SDL_INIT_EVERYTHING | 初始化所有子系统 |
上述定义可以只初始化其中一个子系统,也可以多个一起初始化,多个时用|连接。
返回值
初始化成功返回0,失败返回一个负数错误代码
用法示例
SDL_Init(SDL_INIT_VIDEO); // 只初始化视频子系统
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO); // 初始化视频与音频子系统
// 在初始化的同时进行是否成功判断
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0)
{
SDL_Log("SDL_Init failed: %s", SDL_GetError());
return -1;
}
SDL_Quit
声明
// SDL.h
void SDL_Quit(void);
功能
清除(退出)所有已初始化的子系统。
SDL_CreateWindow
声明
// SDL_video.h
SDL_Window * SDL_CreateWindow(const char *title, int x, int y, int w,int h, Uint32 flags);
功能
参数
| 参数 | 含义 |
|---|---|
| title | 窗口标题,UTF-8编码 |
| x | 窗口起始位置x坐标 通常为居中SDL_WINDOWPOS_CENTERED或未定义SDL_WINDOWPOS_UNDEFINED |
| y | 窗口起始位置y坐标 通常为居中SDL_WINDOWPOS_CENTERED或未定义SDL_WINDOWPOS_UNDEFINED |
| w | 窗口宽度 |
| h | 窗口高度 |
| flags | 窗口显示标志,可以是0,或者是枚举类型SDL_WindowFlags中多个标志组合 |
flags可取值为枚举类型SDL_WindowFlags(定义在SDL_video.h中),多个值时用|连接,一些常用值如下
typedef enum
{
SDL_WINDOW_FULLSCREEN = 0x00000001, // 全屏显示
SDL_WINDOW_OPENGL = 0x00000002, // 使用OpenGL
SDL_WINDOW_SHOWN = 0x00000004, // 显示窗口
SDL_WINDOW_HIDDEN = 0x00000008, // 隐藏窗口
SDL_WINDOW_BORDERLESS = 0x00000010, // 窗口无边框
SDL_WINDOW_RESIZABLE = 0x00000020, // 窗口大小可变
SDL_WINDOW_MINIMIZED = 0x00000040, // 窗口最大化
SDL_WINDOW_MAXIMIZED = 0x00000080, // 窗口最小化
SDL_WINDOW_MOUSE_GRABBED = 0x00000100,
SDL_WINDOW_INPUT_FOCUS = 0x00000200,
SDL_WINDOW_MOUSE_FOCUS = 0x00000400,
SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
SDL_WINDOW_FOREIGN = 0x00000800,
SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,
SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,
SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000, // 窗口保持在最顶层
SDL_WINDOW_SKIP_TASKBAR = 0x00010000,
SDL_WINDOW_UTILITY = 0x00020000,
SDL_WINDOW_TOOLTIP = 0x00040000,
SDL_WINDOW_POPUP_MENU = 0x00080000,
SDL_WINDOW_KEYBOARD_GRABBED = 0x00100000, //
SDL_WINDOW_VULKAN = 0x10000000,
SDL_WINDOW_METAL = 0x20000000,
SDL_WINDOW_INPUT_GRABBED = SDL_WINDOW_MOUSE_GRABBED
} SDL_WindowFlags;
返回值
窗口创建成功则返回对应窗口指针,失败则返回NULL。
SDL_DestroyWindow
声明
// SDL_video.h
void SDL_DestroyWindow(SDL_Window * window);
功能
销毁由SDL_CreateWindow创建的窗口。
用法示例
SDL_Window *window = SDL_CreateWindow(
"SDLWindow",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT,
SDL_WINDOW_SHOWN);
if (NULL == window)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
SDL_Delay(5000);
SDL_DestroyWindow(window);
SDL_Delay
声明
// SDL_timer.h
void SDL_Delay(Uint32 ms);
功能
让程序暂停(阻塞)指定时间,单位为毫秒。
SDL_Log
声明
// SDL_log.h
void SDL_Log(const char *fmt, ...)
功能
向控制台输出信息,用法与C语言中printf一样。
SDL_GetError
声明
// SDL_error.h
const char * SDL_GetError(void);
功能
获取最后一次发生错误对应的错误信息。
SDL_GetWindowSurface
声明
// SDL_video.h
SDL_Surface * SDL_GetWindowSurface(SDL_Window * window);
功能
获取与window关联的SDL_Surface指针。
返回值
成功则返回SDL_Surface指针,失败则返回NULL。
SDL_FreeSurface
声明
// SDL_surface.h
void SDL_FreeSurface(SDL_Surface * surface);
功能
释放SDL_Surface指针。
SDL_FillRect
声明
// SDL_surface.h
int SDL_FillRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color);
功能
在指定的surface上绘制(填充)一个指定区域的矩形。
参数
| 参数 | 含义 |
|---|---|
| dst | 需要在上面进行绘制的surface指针 |
| rect | 需要绘制的区域 |
| color | 4字节无符号整型,表示颜色,通常用十六进制表示,例如0xFF32BACD。每两个字符表示一个通道,分别人ARGB通道。但在本函数中透明通道A不会生效,所以可以只写RGB三个字节,即0x32BACD |
区域结构体见SDL_Rect
返回值
填充成功返回0,失败返回负数错误代码。
SDL_UpdateWindowSurface
声明
// SDL_video.h
int SDL_UpdateWindowSurface(SDL_Window * window);
功能
将Surface的数据更新到屏幕上
返回值
更新成功返回0,失败返回负数错误代码
SDL_MapRGB
声明
// SDL_pixels.h
Uint32 SDL_MapRGB(const SDL_PixelFormat * format,Uint8 r, Uint8 g, Uint8 b);
功能
使用指定的像素格式将r, g, b三个通道的颜色分量转为一个颜色值。
参数
| 参数 | 含义 |
|---|---|
| format | 描述像素格式的结构体 |
| r | 红色通道分量值,0~255 |
| g | 绿色通道分量值, 0~255 |
| b | 蓝色通道分量值, 0~255 |
返回值
由三个分量合并成的像素颜色值。
SDL_MapRGBA
声明
// SDL_pixels.h
Uint32 SDL_MapRGBA(const SDL_PixelFormat * format,Uint8 r, Uint8 g, Uint8 b, Uint8 a);
功能
使用指定的像素格式将r, g, b, a 四个通道的颜色分量转为一个颜色值。
参数
| 参数 | 含义 |
|---|---|
| format | 描述像素格式的结构体 |
| r | 红色通道分量值,0~255 |
| g | 绿色通道分量值, 0~255 |
| b | 蓝色通道分量值, 0~255 |
| a | 透明通道分量值, 0~255 |
返回值
由三个分量合并成的像素颜色值。
SDL_LoadBMP
声明
// SDL_surface.h
#define SDL_LoadBMP(file) SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1)
// SDL_LoadBMP的声明是一个宏定义,其效果等同于下面的写法
SDL_Surface * SDL_LoadBMP_RW(const char * file);
功能
导入BMP图片数据。
参数
file: 文件名
返回值
导入成功返回一个指向SDL_Surface的指针,导入失败则返回NULL。
SDL_BlitSurface
声明
// SDL_surface.h
#define SDL_BlitSurface SDL_UpperBlit
int SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,SDL_Surface * dst, SDL_Rect * dstrect);
功能
将一个surface的内容复制到另一个surface当中。
参数
| 参数 | 含义 |
|---|---|
| src | 源surface |
| srcrect | 源surface需要复制的区域 |
| dst | 目标surface |
| dstrect | 目标surface的区域(不生效) |
返回值
复制成功返回0,失败返回负数错误码。
SDL_BlitScaled
声明
// SDL_surface.h
#define SDL_BlitScaled SDL_UpperBlitScaled
int SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,SDL_Surface * dst, SDL_Rect * dstrect);
功能
将一个surface的内容复制到另一个surface当中。两个区域大小不一致时,进行缩放。
参数
| 参数 | 含义 |
|---|---|
| src | 源surface |
| srcrect | 源surface需要复制的区域 |
| dst | 目标surface |
| dstrect | 目标surface的区域 |
返回值
复制成功返回0,失败返回负数错误码。
SDL_CreateRGBSurface
SDL_CreateRGBSurfaceWithFormat
SDL_CreateRGBSurfaceFrom
SDL_CreateRGBSurfaceWithFormatFrom
SDL_LockSurface
SDL_UnlockSurface
SDL_CreateRenderer
声明
// SDL_render.h
SDL_Renderer * SDL_CreateRenderer(SDL_Window * window,int index, Uint32 flags);
功能
给指定窗口创建一个2D渲染环境。
参数
| 参数 | 含义 |
|---|---|
| window | 需要创建渲染环境的窗口指针 |
| index | 初始化渲染驱动索引。通常为-1,表示自动初始化第一个支持的驱动 |
| flags | 0或者SDL_RendererFlags一个或多个值的组合 |
SDL_RendererFlags为枚举类型,多个值时用|连接。如下
// SDL_render.h
typedef enum
{
SDL_RENDERER_SOFTWARE = 0x00000001, // 软件(CPU)渲染
SDL_RENDERER_ACCELERATED = 0x00000002, // 硬件加速
SDL_RENDERER_PRESENTVSYNC = 0x00000004,
SDL_RENDERER_TARGETTEXTURE = 0x00000008
} SDL_RendererFlags;
返回值
成功返回渲染器指针,失败返回NULL。
SDL_DestroyRenderer
声明
// SDL_render.h
void SDL_DestroyRenderer(SDL_Renderer * renderer);
功能
销毁渲染环境并释放关联的texture
SDL_SetRenderDrawColor
声明
// SDL_render.h
int SDL_SetRenderDrawColor(SDL_Renderer * renderer,Uint8 r, Uint8 g, Uint8 b,Uint8 a);
功能
设置绘制操作(绘制/填充矩形、线条、点以及清除屏幕)的颜色。
参数
| 参数 | 含义 |
|---|---|
| render | 渲染器 |
| r | 红色通道值 |
| g | 绿色通道值 |
| b | 蓝色通道值 |
| a | 透明通道值 |
返回值
设置成功返回0,失败返回负数错误代码。
SDL_RenderClear
声明
// SDL_render.h
int SDL_RenderClear(SDL_Renderer * renderer);
功能
利用SDL_SetRenderDrawColor设置的颜色清除当前渲染目标。
返回值
清除成功返回0,失败返回负数错误码。
SDL_RenderPresent
声明
// SDL_render.h
void SDL_RenderPresent(SDL_Renderer * renderer);
功能
将渲染操作的数据更新到屏幕上。
SDL_SetRenderDrawBlendMode
声明
// SDL_render.h
int SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer,SDL_BlendMode blendMode);
功能
为绘制操作设置颜色混合模式。
参数
混合模式为枚举类型SDL_BlendMode,定义及常用值如下:
// SDL_blendmode.h
typedef enum
{
SDL_BLENDMODE_NONE = 0x00000000, // 默认模式。无混合,透明通道不生效
SDL_BLENDMODE_BLEND = 0x00000001, // Alpha通道混合,透明通道生效
// 下面这些混合模式暂时不用管, 有兴趣可以自行研究一下
SDL_BLENDMODE_ADD = 0x00000002,
SDL_BLENDMODE_MOD = 0x00000004,
SDL_BLENDMODE_MUL = 0x00000008,
SDL_BLENDMODE_INVALID = 0x7FFFFFFF
} SDL_BlendMode;
SDL_RenderDrawPoint
声明
// SDL_render.h
int SDL_RenderDrawPoint(SDL_Renderer * renderer,int x, int y);
功能
根据提供的坐标在当前渲染目标上绘制一个点。
返回值
绘制成功返回0,失败返回负值错误码。
SDL_RenderDrawPoints
声明
// SDL_render.h
int SDL_RenderDrawPoints(SDL_Renderer * renderer,const SDL_Point * points,int count);
功能
在当前渲染环境上绘制多个点。
参数
| 参数 | 含义 |
|---|---|
| renderer | 当前渲染器指针 |
| points | 指向一个SDL_Point数组的指针 |
| count | 点的数量 |
返回值
绘制成功则返回0,失败返回负数错误码。
SDL_RenderDrawLine
声明
// SDL_render.h
int SDL_RenderDrawLine(SDL_Renderer * renderer,int x1, int y1, int x2, int y2);
功能
根据提供的两个点的坐标在当前渲染环境上绘制一条线。
返回值
绘制成功返回0,失败返回负数错误码。
SDL_RenderDrawLines
声明
// SDL_render.h
int SDLCALL SDL_RenderDrawLines(SDL_Renderer * renderer,const SDL_Point * points,int count);
功能
沿着提供的多个点绘制线段。
参数
返回值
绘制成功返回0,失败返回负数错误码。
SDL_RenderDrawRect
声明
// SDL_render.h
int SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect);
功能
在当前渲染目标上指定区域绘制一个矩形。
返回值
绘制成功返回0,失败返回负数错误码。
SDL_RenderDrawRects
声明
// SDL_render.h
int SDL_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count);
功能
根据提供的区域数组在当前渲染目标上绘制多个矩形。
参数
| 参数 | 含义 |
|---|---|
| renderer | 渲染器指针 |
| rects | 指向SDL_Rect数组的指针 |
| count | 区域数量 |
返回值
绘制成功返回0,失败返回负数错误码。
SDL_RenderFillRect
声明
// SDL_render.h
int SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect);
功能
在当前渲染目标上指定区域填充一个矩形。
返回值
填充成功返回0,失败返回负数错误码。
SDL_RenderFillRects
声明
// SDL_render.h
int SDL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count);
功能
根据提供的区域数组在当前渲染目标上填充多个矩形。
参数
| 参数 | 含义 |
|---|---|
| renderer | 渲染器指针 |
| rects | 指向SDL_Rect数组的指针 |
| count | 区域数量 |
返回值
填充成功返回0,失败返回负数错误码。
SDL_RenderSetScale
SDL_CreateTextureFromSurface
声明
// SDL_render.h
DL_Texture * SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface);
功能
由已存在的Surface创建Texture。
返回值
创建成功返回对应SDL_Texture指针,失败返回NULL。
SDL_DestroyTexture
声明
// SDL_render.h
void SDL_DestroyTexture(SDL_Texture * texture);
功能
销毁指定的Texture。
SDL_RenderCopy
声明
// SDL_render.h
int SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect);
功能
从Texture中复制指定部分到渲染目标中。当源区域与指定区域大小不一致时,会进行相应缩放。
参数
| 参数 | 含义 |
|---|---|
| renderer | 渲染器指针 |
| texture | 需要进行复制的texture |
| srcrect | 需要进行复制的源区域,NULL表示整个区域 |
| dstrect | 需要进行复制的目标区域,NULL表示整个区域 |
SDL_RenderCopyEx
声明
// SDL_render.h
int SDLCALL SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect, const double angle, const SDL_Point *center, const SDL_RendererFlip flip);
功能
从Texture中复制指定部分到渲染目标中, 同时可进行旋转和镜像翻转操作。
参数
| 参数 | 含义 |
|---|---|
| render | 渲染器指针 |
| texture | 需要进行复制的Texture |
| srcrect | 需要进行复制的源区域,NULL表示整个区域 |
| dstrect | 复制去的目标区域,NULL表示整个渲染目标区域 |
| angle | 旋转角度,顺时针方向旋转 |
| center | 旋转中心点,为相对dstrect左上角的坐标。NULL表示围绕dstrect中心旋转 |
| flip | 镜像翻转。为枚举类型SDL_RendererFlip,见下 |
// SDL_render.h
typedef enum
{
SDL_FLIP_NONE = 0x00000000, // 不进行翻转
SDL_FLIP_HORIZONTAL = 0x00000001, // 进行水平镜像翻转
SDL_FLIP_VERTICAL = 0x00000002 // 进行垂直镜像翻转
} SDL_RendererFlip;
SDL_SetTextureAlphaMod
声明
// SDL_render.h
int SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha);
功能
为render copy设置透明度,需要配合SDL_SetTextureBlendMode使用。
返回值
设置成功返回0,失败返回负数错误码。
SDL_SetTextureBlendMode
声明
// SDL_render.h
int SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode);
功能
为SDL_RenderCopy设置颜色混合模式。
参数
SDL_BlendMode见SDL_SetRenderDrawBlendMode参数。
返回值
成功返回0,失败返回负数错误码。
SDL_UpdateTexture
SDL_UpdateYUVTexture
SDL_UpdateNVTexture
SDL_LockTexture
SDL_LockTextureToSurface
SDL_UnlockTexture
SDL_PointInRect
声明
// SDL_rect.h
SDL_bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r);
功能
判断一个点是否在一个区域中。
参数
返回值
点在区域内返回SDL_TRUE, 点不在区域内返回SDL_FALSE。
SDL_RectEmpty
声明
// SDL_rect.h
SDL_bool SDL_RectEmpty(const SDL_Rect *r);
功能
判断一个区域是否面积。
参数
返回值
如果r为NULL或者对应区域面积(计算值)小于或等于0则返回SDL_TRUE,否则返回SDL_FALSE。
SDL_RectEquals
声明
// SDL_rect.h
SDL_bool SDL_RectEquals(const SDL_Rect *a, const SDL_Rect *b);
功能
判断两个区域是否相同。
参数
返回值
如果两个SDL_Rect指针都不为NULL,且左上角坐标相同、宽高也相同则返回SDL_TRUE,否则返回SDL_FALSE。
SDL_HasIntersection
声明
// SDL_rect.h
SDL_bool SDL_HasIntersection(const SDL_Rect * A,const SDL_Rect * B);
功能
判断两个矩形区域是否有相交部分。
参数
返回值
如果两个SDL_Rect指针都不为NULL且有相交部分则返回SDL_TRUE,否则返回SDL_FALSE。
SDL_IntersectRect
声明
// SDL_rect.h
SDL_bool SDLCALL SDL_IntersectRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result);
功能
计算两个矩形区域相交部分。
参数
A,B: 需要计算的两个区域
result: A与B相交的部分。
返回值
如果A、B有相交部分则返回SDL_TRUE,否则返回SDL_FALSE。
SDL_UnionRect
声明
// SDL_rect.h
void SDLCALL SDL_UnionRect(const SDL_Rect * A, const SDL_Rect * B, SDL_Rect * result);
功能
计算两个矩形区域的并集。如果A、B是两个分离开的区域,则并为能将A、B两个区域包含在内的最小矩形区域。
参数
A,B: 需要计算的两个区域
result: A与B并集。
SDL_LoadWAV
声明
// SDL_audio.h
#define SDL_LoadWAV(file, spec, audio_buf, audio_len) \
SDL_LoadWAV_RW(SDL_RWFromFile(file, "rb"),1, spec,audio_buf,audio_len)
SDL_AudioSpec * SDL_LoadWAV_RW(SDL_RWops * src, int freesrc, SDL_AudioSpec * spec, Uint8 ** audio_buf, Uint32 * audio_len);
功能
导入WAV格式音频文件。
参数
| 参数 | 含义 |
|---|---|
| file | WAV文件名 |
| spec | SDL_AudioSpec,音频文件信息 |
| audio_buf | 音频文件数据指针 |
| audio_len | 音频文件长度(字节)指针 |
返回值
成功返回SDL_AudioSpec指针,失败返回NULL。
SDL_FreeWAV
声明
// SDL_audio.h
void SDL_FreeWAV(Uint8 * audio_buf);
功能
释放SDL_LoadWAV导入的音频数据。
SDL_OpenAudioDevice
声明
// SDL_audio.h
SDL_AudioDeviceID SDL_OpenAudioDevice(const char *device, int iscapture, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained, int allowed_changes);
功能
打开指定的音频设备。
参数
| 参数 | 含义 |
|---|---|
| device | 设备名称,由SDL_GetAudioDeviceName获得,为NULL则请求能使用的默认设备 |
| iscapture | 是否是录音设备,0表示播放设备,非0表示录音设备 |
| desired | 期望输出格式。SDL_AudioSpec |
| obtained | 实际输出格式。SDL_AudioSpec |
| allowed_changes | 当硬件不支持时是否允许改变。通常为0 |
返回值
成功则返回一个有效设备ID。失败返回0
SDL_PauseAudioDevice
声明
// SDL_audio.h
void SDL_PauseAudioDevice(SDL_AudioDeviceID dev, int pause_on);
功能
设置指定播放设备的暂停和播放。
参数
dev: 由SDL_OpenAudioDevice打开的设备ID。
pause_on: 暂停/播放,0为播放,非0为暂停。
SDL_GetAudioDeviceName
声明
// SDL_audio.h
const char * SDL_GetAudioDeviceName(int index, int iscapture);
功能
根据索引查询音频设备名称。
参数
index: 设备索引
iscapture: 是否为录音设备。0查询非录音设备,非0查询录音设备。
返回值
查询到设备返回设备名称,否则返回NULL。
结构体、枚举、宏定义
SDL_bool
定义
// SDL_stdinc.h
typedef enum
{
SDL_FALSE = 0,
SDL_TRUE = 1
} SDL_bool;
描述
定义布尔值。虽然也是1为真0为假,但是这样定义之后在代码中使用这个定义可以增加可读性。
SDL_Point
定义
// SDL_rect.h
typedef struct SDL_Point
{
int x; // 点的横坐标
int y; // 点的纵坐标
} SDL_Point;
描述
定义了一个点。
SDL_Rect
定义
// SDL_rect.h
typedef struct SDL_Rect
{
int x, y; //矩形区域左上角坐标
int w, h; // 矩形区域宽和高 单位为像素
} SDL_Rect;
描述
一个由左上角坐标和宽高决定的矩形区域。
SDL_Surface
定义
// SDL_surface.h
typedef struct SDL_Surface
{
Uint32 flags; //
SDL_PixelFormat *format; // 像素格式信息
int w, h; // 宽、高
int pitch; // 每一行像素字节数
void *pixels; // 界面上像素对应的数据内存指针
/** 以下这些成员可以暂时先不用了解 */
void *userdata;
int locked;
void *list_blitmap;
SDL_Rect clip_rect;
SDL_BlitMap *map;
int refcount;
} SDL_Surface;
描述
进行位图操作的像素集。可以理解为一张画布,可以在上面进行绘图和其他像素操作。
SDL_AudioSpec
定义
// SDL_audio.h
typedef struct SDL_AudioSpec
{
int freq; // 采样率
SDL_AudioFormat format; // 音频数据格式
Uint8 channels; // 声道数: 1为单声道 2为立体声
Uint8 silence; //
Uint16 samples; //
Uint16 padding; //
Uint32 size; // 音频数据大小(字节)
SDL_AudioCallback callback; // 为音频设备提供数据的回调函数
void *userdata; // 向回调函数中传递的数据
} SDL_AudioSpec;
描述
保存音频文件一些格式信息。
userdata最主要用于传递SDL_LoadWAV加载进来的audio_buf数据,也可以自定义一些其他数据。
SDL_AudioCallback为回调函数类型,定义如下:
typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,int len);
userdata为通过SDL_AudioSpec传入的userdata,
stream为每次向音频设备传递的声音数据,
len为传递的stream长度。
一个SDL_AudioCallback例子如下:
typedef struct {
Uint8 *audio_buf;
Uint32 audio_len;
Uint32 pos;
} AudioInfo;
void callback(void *userdata, Uint8 * stream, int len)
{
AudioInfo *audio_info = (AudioInfo *)userdata;
Uint32 remain_len = audio_info->audio_len - audio_info->pos;
if (remain_len > len)
{
SDL_memcpy(stream, audio_info->audio_buf + audio_info->pos, len);
audio_info->pos += len;
}
else
{
SDL_memcpy(stream, audio_info->audio_buf + audio_info->pos, remain_len);
audio_info->pos = 0;
}
}
void play_audio()
{
SDL_AudioSpec spec;
Uint8 *audio_buf;
Uint32 audio_len;
if (SDL_LoadWAV("sound.wav", &spec, &audio_buf, &audio_len) == NULL)
{
SDL_Log("wav load failed: %s", SDL_GetError());
return -1;
}
spec.callback = callback;
AudioInfo audio_info = {audio_buf, audio_len, 0};
spec.userdata = &audio_info;
SDL_AudioDeviceID dvice_id = SDL_OpenAudioDevice(NULL, 0, &spec, &spec, 0);
SDL_PauseAudioDevice(dvice_id, SDL_FALSE);
}
Unknown
#include <SDL2/SDL.h>
#define WIDTH 720
#define HEIGHT 720
#define FR 30
#define FT 1000 / FR
SDL_Window *window;
SDL_Renderer *render;
SDL_Surface *image_surface;
SDL_Texture *image_texture;
SDL_Rect render_rect;
void calc_redner_rect()
{
int window_width, window_height, texture_width, texture_height;
SDL_GetWindowSize(window, &window_width, &window_height);
SDL_QueryTexture(image_texture, NULL, NULL, &texture_width, &texture_height);
double scale = 1.0;
if ((texture_width > window_width) && (texture_height > window_height))
{
double xscale = (double)window_width / texture_width;
double yscale = (double)window_height / texture_height;
scale = xscale < yscale ? xscale : yscale;
}
else if (texture_width > window_width)
{
scale = (double)window_width / texture_width;
}
else if (texture_height > window_height)
{
scale = (double)window_height / texture_height;
}
texture_height *= scale;
texture_width *= scale;
render_rect.x = (window_width - texture_width) / 2;
render_rect.y = (window_height - texture_height) / 2;
render_rect.w = texture_width;
render_rect.h = texture_height;
SDL_Log("calc_redner_rect");
}
int initialize()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
SDL_Log("SDL_Init failed: %s", SDL_GetError());
return -1;
}
window = SDL_CreateWindow("SDL",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
if (NULL == window)
{
SDL_Log("SDL_CreateWindow failed: %s", SDL_GetError());
return -1;
}
render = SDL_CreateRenderer(window, -1, 0);
if (NULL == render)
{
SDL_Log("SDL_CreateRenderer error: %s", SDL_GetError());
return -1;
}
image_surface = SDL_LoadBMP("1685074549643.bmp");
if (NULL == image_surface)
{
SDL_Log("Image load failed: %s", SDL_GetError());
return -1;
}
image_texture = SDL_CreateTextureFromSurface(render, image_surface);
if (NULL == image_texture)
{
SDL_Log("SDL_CreateTextureFromSurface failed: %s", SDL_GetError());
return -1;
}
calc_redner_rect();
return 0;
}
void release()
{
if (NULL != image_texture)
{
SDL_DestroyTexture(image_texture);
}
if (NULL != image_surface)
{
SDL_FreeSurface(image_surface);
}
if (NULL != render)
{
SDL_DestroyRenderer(render);
}
if (NULL != window)
{
SDL_DestroyWindow(window);
}
SDL_Quit();
}
void draw()
{
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
SDL_RenderClear(render);
SDL_RenderCopy(render, image_texture, NULL, &render_rect);
SDL_RenderPresent(render);
}
void event_loop()
{
SDL_Event event;
while (1)
{
Uint64 start = SDL_GetTicks64();
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_MOUSEMOTION:
break;
case SDL_MOUSEBUTTONDOWN:
break;
case SDL_MOUSEBUTTONUP:
break;
case SDL_MOUSEWHEEL:
break;
case SDL_QUIT:
return;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
calc_redner_rect();
}
break;
default:
break;
}
}
draw();
Uint64 end = SDL_GetTicks64();
int time = end - start;
// SDL_Log("time = %d, FT = %d", time, FT);
if (time < FT)
{
SDL_Delay(FT - time);
}
}
}
typedef struct {
Uint8 *audio_buf;
Uint32 audio_len;
Uint32 pos;
} AudioInfo;
void callback(void *userdata, Uint8 * stream, int len)
{
AudioInfo *audio_info = (AudioInfo *)userdata;
// SDL_Log("len = %d, len = %d, pos = %u", audio_info->audio_len, len, audio_info->pos);
Uint32 remain_len = audio_info->audio_len - audio_info->pos;
if (remain_len > len)
{
SDL_memcpy(stream, audio_info->audio_buf + audio_info->pos, len);
audio_info->pos += len;
}
else
{
SDL_memcpy(stream, audio_info->audio_buf + audio_info->pos, remain_len);
audio_info->pos = 0;
}
}
void play_wav()
{
}
#undef main
int main(int argc, char *argv[])
{
if (initialize() < 0)
{
release();
return -1;
}
SDL_AudioSpec spec;
Uint8 *audio_buf;
Uint32 audio_len;
if (SDL_LoadWAV("sound.wav", &spec, &audio_buf, &audio_len) == NULL)
{
SDL_Log("wav load failed: %s", SDL_GetError());
return -1;
}
spec.callback = callback;
AudioInfo audio_info = {audio_buf, audio_len, 0};
spec.userdata = &audio_info;
SDL_Log("%u", audio_len);
SDL_AudioDeviceID dvice_id = SDL_OpenAudioDevice(NULL, 0, &spec, &spec, 0);
SDL_PauseAudioDevice(dvice_id, SDL_FALSE);
SDL_Log("Here !");
event_loop();
SDL_CloseAudioDevice(dvice_id);
SDL_FreeWAV(audio_buf);
release();
return 0;
}
CPP多线程





