Development Environment: MacOS
Reference Link: Teacher Chen Yun's SDL2 Tutorial
Note: Study Notes
Drawing Text#
To draw text, we need to use a font library. My suggestion is to use Source Han Sans or De Yi Ti created by Bilibili user oooooohmygosh. Both fonts are open source and free to use.
We also need to download the SDL2_image
library:
Use brew to download brew install sdl2_image
Then use brew info sdl2_image
to check the location.
Finally, configure CMake as follows:
cmake_minimum_required(VERSION 3.23.2)
project(DrewText C)
set(CMAKE_C_STANDARD 11)
# SDL2
set(SDL_DIR /usr/local/Cellar/sdl2/2.26.0)
include_directories(${SDL_DIR}/include/SDL2)
link_directories(${SDL_DIR}/lib/)
# SDL2_image
set(SDL2_image /usr/local/Cellar/sdl2_image/2.6.2)
include_directories(${SDL2_image}/include/)
link_directories(${SDL2_image}/lib/)
# SDL2_ttf
set(SDL2_ttf /usr/local/Cellar/sdl2_ttf/2.20.1)
include_directories(${SDL2_ttf}/include/)
link_directories(${SDL2_ttf}/lib/)
link_libraries(SDL2)
link_libraries(SDL2_image)
link_libraries(SDL2_ttf)
# Move the executable file out to prevent resource (ttf/image) not found
set(EXECUTABLE_OUTPUT_PATH ../)
add_executable(DrewText main.c)
Open the font in the main
function:
/* Open the font */
font = TTF_OpenFont("font file path", FONT_SIZE);
if (font==NULL) {
SDL_Log("Can not open font");
}
Don't forget to release it:
...
/* Close the font */
TTF_CloseFont(font);
...
Then write a draw
function to render the font:
void draw(SDL_Surface * screen, SDL_Window * win) {
// Render text
/* Font color */
SDL_Color color = {225, 0, 0, 255}; // RGBA
/* Render text */
SDL_Surface * text = TTF_RenderUTF8_Blended(font, "I really like Dong Xuelian", color); // Font, content, font (foreground) color
/* Display on the main screen */
// Rectangle
SDL_Rect text_src = {0, 0, text->w, text->h};
// Render to
SDL_BlitSurface(text, &text_src, screen, &text_src);
// Update the main screen
SDL_UpdateWindowSurface(win);
}
Then just run it.
About Frame Rate Detection#
First, what is frame rate?
Frame rate is a measure used to indicate the number of frames being displayed per second. The unit of measurement is "frames per second" (FPS) or "hertz". Generally, FPS is used to describe how many frames are played per second in videos, electronic graphics, or games. -- Wikipedia
So it's quite simple to implement. We just need to know the time when the rendering starts and subtract the time when it ends to get the current frame rate.
Therefore, we need to set a value at the beginning of the program's main loop. SDL2 provides us with the SDL_GetTicks()
function, which allows us to easily get the time when the program starts.
/* Frame rate: Get the millisecond value */
long begin = SDL_GetTicks();
Then subtract the start time from the end time:
/* Frame rate: Current value */
long current = SDL_GetTicks();
/* Time spent per frame now */
long cost = current - begin;
We can also lock the frame rate to maintain a stable value:
// Set the frame rate
#define FRAMERATE 60
...
/* Time per frame */
long frame = 1000/FRAMERATE;
/* Calculate the time to sleep to maintain the frame rate */
long delay = frame - cost;
/* If the delay is negative, do not sleep to maintain the frame rate */
if (delay > 0) {
SDL_Delay(delay);
}
/* In the case of sufficient system resources, it can maintain a sufficient frame rate. If not, there is nothing we can do */
About the Viewport#
Setting the viewport allows us to conditionally limit the display of everything.
For example, if I want everything to be displayed in a 300*300 matrix with x=10
, y=50
, I can write it like this:
// Destination box parameters
struct SDL_Rect viewport = {10, 50, 300, 300};
// renderer is the renderer
SDL_RenderSetViewport(renderer, &viewport);
You will find that everything rendered with the renderer is now inside the destination box.