- [Description] Course learning address: https://ke.qq.com/course/468797
table of Contents
Linux environment construction
SDL Window display: Introduction to SDL video display function
Introduction to SDL
- Official website: https://www.libsdl.org/
- Documentation: http://wiki.libsdl.org/Introduction
- SDL (Simple DirectMedia Layer) is a set of open source cross-platform multimedia development libraries written in C language.
- SDL provides several functions for controlling images, sounds, and I/O , allowing developers to develop application software across multiple platforms (Linux, Windows, Mac OS X, etc.) as long as they use the same or similar code.
- At present, SDL is mostly used in the development of multimedia applications such as games, simulators, and media players.
Windows environment setup
- Download link: https://www.libsdl.org/download-2.0.php
Linux environment construction
- Download the SDL source code library, SDL2-2.0.10.tar.gz
- Unzip, and then execute the commands in turn
./configure make sudo make install
- If the Could not initialize SDL-No available video device (Did you set the DISPLAY variable?) error appears, it means that the x11 library file is not installed in the system, so the compiled SDL library cannot actually be used. Download and install
sudo apt-get install libx11-dev sudo apt-get install xorg-dev
SDL subsystem
- SDL divides functions into the following subsystems:
SDL_INIT_TIMER Timer SDL_INIT_AUDIO Audio SDL_INIT_VIDEO video SDL_INIT_JOYSTICK Joystick SDL_INIT_HAPTIC touch screen SDL_INIT_GAMECONTROLLER Game Controller SDL_INIT_EVENTS event SDL_INIT_EVERYTHING Contains all the above options
SDL Window display: Introduction to SDL video display function
SDL_Init() Initialize the SDL system SDL_CreateWindow() Create window SDL_Window SDL_CreateRenderer() Create renderer SDL_Renderer SDL_CreateTexture() Create texture SDL_Texture SDL_UpdateTexture() Set the texture data SDL_RenderCopy() Copy the texture data to the renderer SDL_RenderPresent () display SDL_Delay() Utility function for delay SDL_Quit() Exit the SDL system
Create project
- Put the decompressed SDL file under the created project
- Add library to project file
- Hold down the Ctrl key and click on the path name to see if the configuration is correct
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 }
- Copy the dynamic library file (SDL2-2.0.10\lib\x64, where 32-bit platform is used here) to the project directory
- Add dynamic library files in the debug directory
- carry out testing
#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; }
- Output:
SDL Windows display: Introduction to SDL data structure
- SDL_Window represents a "window"
- SDL_Renderer represents a "renderer"
- SDL_Texture represents a "texture"
- SDL_Rect a simple rectangular structure
- The difference between storing RGB and storing texture:
- For example, for a rectangle that changes from red to blue from left to right, if RGB is used, the specific color value of each point in the rectangle needs to be stored.
- The texture is just some descriptive information, such as the size of the rectangle, the starting color, the ending color, and other information. The graphics card can use this information to calculate the detailed information of the rectangular block.
- So compared to storing RGB, the memory used to store textures is much less.
- Example:
#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; }
- Show results:
SDL events
SDL_WaitEvent() Waiting for an event SDL_PushEvent() Send an event SDL_PumpEvents() Put the events generated by the hardware device into the event queue for reading events. Before calling this function, you must call SDL_PumpEvents to collect keyboard events and other events SDL_PeepEvents() Extract an event from the event queue SDL_Event Represents an event
- Example:
#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 multithreading
SDL thread creation SDL_CreateThread SDL thread waiting SDL_WaitThead SDL Mutex SDL_CreateMutex/SDL_DestroyMutex SDL lock mutex SDL_LockMutex/SDL_UnlockMutex SDL condition variable (semaphore) SDL_CreateCond/SDL_DestoryCond SDL condition variable (semaphore) wait/notify SDL_CondWait/SDL_CondSingal
- Example:
#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; }
- Output: