- 【说明】课程学习地址:https://ke.qq.com/course/468797
目录
SDL简介
- 官网: https://www.libsdl.org/
- 文档: http://wiki.libsdl.org/Introduction
- SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。
- SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、 Windows、 Mac OS X等)的应用软件。
- 目前SDL多用于开发游戏、模拟器、 媒体播放器等多媒体应用领域。
Windows环境搭建
Linux环境搭建
- 下载SDL源码库, SDL2-2.0.10.tar.gz
- 解压,然后依次执行命令
./configure make sudo make install
- 如果出现Could not initialize SDL - No available video device(Did you set the DISPLAY variable?)错误说明系统中没有安装x11的库文件,因此编译出来的SDL库实际上不能用。下载安装
sudo apt-get install libx11-dev sudo apt-get install xorg-dev
SDL子系统
- SDL将功能分成下列数个子系统(subsystem):
SDL_INIT_TIMER 定时器 SDL_INIT_AUDIO 音频 SDL_INIT_VIDEO 视频 SDL_INIT_JOYSTICK 摇杆 SDL_INIT_HAPTIC 触摸屏 SDL_INIT_GAMECONTROLLER 游戏控制器 SDL_INIT_EVENTS 事件 SDL_INIT_EVERYTHING 包含上述所有选项
SDL Window显示: SDL视频显示函数简介
SDL_Init() 初始化SDL系统 SDL_CreateWindow() 创建窗口SDL_Window SDL_CreateRenderer() 创建渲染器SDL_Renderer SDL_CreateTexture() 创建纹理SDL_Texture SDL_UpdateTexture() 设置纹理的数据 SDL_RenderCopy() 将纹理的数据拷贝给渲染器 SDL_RenderPresent() 显示 SDL_Delay() 工具函数,用于延时 SDL_Quit() 退出SDL系统
创建项目
- 将解压的SDL文件放入创建的项目下
- 在工程文件中添加库
- 按住Ctrl键点击路径名称,可查看是否配置正确
TEMPLATE = app CONFIG += console CONFIG -= app_bundle CONFIG -= qt SOURCES += \ main.c win32 { INCLUDEPATH += $$PWD/SDL2-2.0.10/include LIBS += $$PWD/SDL2-2.0.10/lib/x86/SDL2.lib }
- 将动态库文件(SDL2-2.0.10\lib\x64,这里使用32位平台)复制到工程目录下
- debug目录下添加动态库文件
- 进行测试
#include <stdio.h> #include <SDL.h> #undef main int main() { printf("Hello World!\n"); // 声明窗口 SDL_Window *window = NULL; // 初始化SDL SDL_Init(SDL_INIT_VIDEO); // 创建SDL Window window = SDL_CreateWindow("Basic Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if(!window) // 检测是否创建成功 { printf("Can't create window, err:%s\n", SDL_GetError()); return 1; } // 延迟10000ms SDL_Delay(10000); // 销毁窗口 SDL_DestroyWindow(window); // 释放资源 SDL_Quit(); return 0; }
- 输出:
SDL Windows显示: SDL数据结构简介
- SDL_Window 代表了一个“窗口”
- SDL_Renderer 代表了一个“渲染器”
- SDL_Texture 代表了一个“纹理”
- SDL_Rect 一个简单的矩形结构
- 存储RGB和存储纹理的区别:
- 比如一个从左到右由红色渐变到蓝色的矩形,用存储RGB的话就需要把矩形中每个点的具体颜色值存储下来。
- 纹理只是一些描述信息,比如记录了矩形的大小、起始颜色、终止颜色等信息,显卡可以通过这些信息推算出矩形块的详细信息。
- 所以相对于存储RGB而已,存储纹理占用的内存要少的多。
- 示例:
#include <stdio.h> #include <SDL.h> #undef main int main() { int run = 1; SDL_Window *window = NULL; SDL_Renderer *renderer = NULL; SDL_Texture *texture = NULL; SDL_Rect rect; // 长方形,原点在左上角 rect.w = 50; //方块大小 rect.h = 50; SDL_Init(SDL_INIT_VIDEO);//初始化函数,可以确定希望激活的子系统 window = SDL_CreateWindow("2 Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);// 创建窗口 if (!window) { return -1; } renderer = SDL_CreateRenderer(window, -1, 0);//基于窗口创建渲染器 if (!renderer) { return -1; } texture = SDL_CreateTexture(renderer, //基于渲染器创建纹理 SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 640, 480); //创建纹理 if (!texture) { return -1; } int show_count = 0; while (run) { rect.x = rand() % 600; rect.y = rand() % 400; SDL_SetRenderTarget(renderer, texture); // 设置渲染目标为纹理 SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255); // 纹理背景颜色设置 SDL_RenderClear(renderer); //清屏 SDL_RenderDrawRect(renderer, &rect); //绘制一个长方形 SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255); //长方形颜色设置 SDL_RenderFillRect(renderer, &rect); SDL_SetRenderTarget(renderer, NULL); //恢复默认,渲染目标为窗口 SDL_RenderCopy(renderer, texture, NULL, NULL); //拷贝纹理到CPU SDL_RenderPresent(renderer); //输出到目标窗口上 SDL_Delay(300); if(show_count++ > 30) { run = 0; // 不跑了 } } SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); //销毁窗口 SDL_Quit(); return 0; }
- 显示结果:
SDL事件
SDL_WaitEvent() 等待一个事件 SDL_PushEvent() 发送一个事件 SDL_PumpEvents() 将硬件设备产生的事件放入事件队列,用于读取事件,在调用该函数之前,必须调用SDL_PumpEvents搜集键盘等事件 SDL_PeepEvents() 从事件队列提取一个事件 SDL_Event 代表一个事件
- 示例:
#include <SDL.h> #include <stdio.h> #define FF_QUIT_EVENT (SDL_USEREVENT + 2) // 用户自定义事件 #undef main int main(int argc, char* argv[]) { SDL_Window *window = NULL; // Declare a pointer SDL_Renderer *renderer = NULL; SDL_Init(SDL_INIT_VIDEO); // Initialize SDL2 // Create an application window with the following settings: window = SDL_CreateWindow( "An SDL2 window", // window title SDL_WINDOWPOS_UNDEFINED, // initial x position SDL_WINDOWPOS_UNDEFINED, // initial y position 640, // width, in pixels 480, // height, in pixels SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS// flags - see below ); // Check that the window was successfully created if (window == NULL) { // In the case that the window could not be made... printf("Could not create window: %s\n", SDL_GetError()); return 1; } /* We must call SDL_CreateRenderer in order for draw calls to affect this window. */ renderer = SDL_CreateRenderer(window, -1, 0); /* Select the color for drawing. It is set to red here. */ SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); /* Clear the entire screen to our selected color. */ SDL_RenderClear(renderer); /* Up until now everything was drawn behind the scenes. This will show the new, red contents of the window. */ SDL_RenderPresent(renderer); SDL_Event event; int b_exit = 0; for (;;) { SDL_WaitEvent(&event); switch (event.type) { case SDL_KEYDOWN: /* 键盘事件 */ switch (event.key.keysym.sym) { case SDLK_a: printf("key down a\n"); break; case SDLK_s: printf("key down s\n"); break; case SDLK_d: printf("key down d\n"); break; case SDLK_q: printf("key down q and push quit event\n"); SDL_Event event_q; event_q.type = FF_QUIT_EVENT; SDL_PushEvent(&event_q); break; default: printf("key down 0x%x\n", event.key.keysym.sym); break; } break; case SDL_MOUSEBUTTONDOWN: /* 鼠标按下事件 */ if (event.button.button == SDL_BUTTON_LEFT) { printf("mouse down left\n"); } else if(event.button.button == SDL_BUTTON_RIGHT) { printf("mouse down right\n"); } else { printf("mouse down %d\n", event.button.button); } break; case SDL_MOUSEMOTION: /* 鼠标移动事件 */ printf("mouse movie (%d,%d)\n", event.button.x, event.button.y); break; case FF_QUIT_EVENT: printf("receive quit event\n"); b_exit = 1; break; } if(b_exit) break; } //destory renderer if (renderer) SDL_DestroyRenderer(renderer); // Close and destroy the window if (window) SDL_DestroyWindow(window); // Clean up SDL_Quit(); return 0; }
SDL多线程
SDL线程创建 SDL_CreateThread SDL线程等待 SDL_WaitThead SDL互斥锁 SDL_CreateMutex/SDL_DestroyMutex SDL锁定互斥 SDL_LockMutex/SDL_UnlockMutex SDL条件变量(信号量) SDL_CreateCond/SDL_DestoryCond SDL条件变量(信号量)等待/通知 SDL_CondWait/SDL_CondSingal
- 示例:
#include <SDL.h> #include <stdio.h> SDL_mutex *s_lock = NULL; SDL_cond *s_cond = NULL; int thread_work(void *arg) { SDL_LockMutex(s_lock); printf(" <============thread_work sleep\n"); sleep(10); // 用来测试获取锁 printf(" <============thread_work wait\n"); // 释放s_lock资源,并等待signal。之所以释放s_lock是让别的线程能够获取到s_lock SDL_CondWait(s_cond, s_lock); //另一个线程(1)发送signal和(2)释放lock后,这个函数退出 printf(" <===========thread_work receive signal, continue to do ~_~!!!\n"); printf(" <===========thread_work end\n"); SDL_UnlockMutex(s_lock); return 0; } #undef main int main() { s_lock = SDL_CreateMutex(); s_cond = SDL_CreateCond(); SDL_Thread * t = SDL_CreateThread(thread_work,"thread_work",NULL); if(!t) { printf(" %s",SDL_GetError); return -1; } for(int i = 0;i< 2;i++) { sleep(2); printf("main execute =====>\n"); } printf("main SDL_LockMutex(s_lock) before ====================>\n"); SDL_LockMutex(s_lock); // 获取锁,但是子线程还拿着锁 printf("main ready send signal====================>\n"); printf("main SDL_CondSignal(s_cond) before ====================>\n"); SDL_CondSignal(s_cond); // 发送信号,唤醒等待的线程 printf("main SDL_CondSignal(s_cond) after ====================>\n"); sleep(10); SDL_UnlockMutex(s_lock);// 释放锁,让其他线程可以拿到锁 printf("main SDL_UnlockMutex(s_lock) after ====================>\n"); SDL_WaitThread(t, NULL); SDL_DestroyMutex(s_lock); SDL_DestroyCond(s_cond); return 0; }
- 输出: