In this section, we will examine a program that prints a given string of characters to the screen by loading font images from an image file into a texture.
When the program runs, in addition to the basic operations, the following operations occur:
struct char_val { int x; int w; } char_vals[CHAR_COUNT];
The contents of the main.c file will be as follows:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480
#define CHAR_COUNT 106
// Global variables
int is_running = false; // Variable that controls the execution of the main loop of the program
SDL_Window *window = NULL; // Main window variable
SDL_Texture *texture_font = NULL; // Texture variable
SDL_Renderer *renderer = NULL; // Renderer variable
int char_height;
struct char_val {
int x;
int w;
} char_vals[CHAR_COUNT];
// Function prototypes
int init_window(void); // Create window and renderer
void init_vars(void); // Initialize variables
void load_img(void); // Load image to texture
void process_event(void); // Process events
void update_screen(); // Update values
void draw_screen(void); // Draw screen
void destroy_window(void); // Destroy window
void draw_text(int x, int y, char* text);
int main(int argc, char* argv[])
{
// Create window and renderer
is_running = init_window();
// Initialize variables
init_vars();
// Load .png file to texture
load_img();
// Main loop
while (is_running) {
process_event(); // Processing SDL events (Here keyboard inputs).
update_screen(); // Updating variables
draw_screen(); // Drawing objects on the window (Rendering)
}
// Destroy renderer and SDL window
destroy_window();
return 0;
}
// Create window and renderer
int init_window(void)
{
// Initialize the SDL library.
if(SDL_Init(SDL_INIT_VIDEO) == false) {
SDL_Log("SDL init error: %s\n", SDL_GetError());
return false;
}
// Create a window and a 2D rendering context for the window.
if(!SDL_CreateWindowAndRenderer("SDL3 window", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) {
return false;
}
return true;
}
// Load image to texture
void load_img(void)
{
texture_font = IMG_LoadTexture(renderer, "arial.png");
if(texture_font == NULL) {
SDL_Log("IMG_LoadTexture error: %s\n", SDL_GetError());
}
}
// Initialization function that runs only once at the beginning of the program
void init_vars(void)
{
char_height = 70;
const char *filename = "char_data.bin";
// Read from file
FILE *file = fopen(filename, "rb");
if(file == NULL) {
SDL_Log("File open error!\n");
}
size_t read = fread(char_vals, sizeof(struct char_val), CHAR_COUNT, file);
if(read != CHAR_COUNT) {
SDL_Log("File read error!\n");
}
fclose(file);
}
// Function to control SDL events and process keyboard inputs
void process_event(void)
{
SDL_Event event;
// Creating a loop to process user inputs
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_EVENT_QUIT: // Logout action by the user (x button at the top right of the window)
is_running = false;
break;
case SDL_EVENT_KEY_DOWN: // Key pressed
switch(event.key.key) {
case SDLK_UP: if(char_height<70) char_height += 5; break; // Increase char height
case SDLK_DOWN: if(char_height>35) char_height -= 5; break; // Decrease char height
case SDLK_ESCAPE: is_running = false; break;
}
break;
}
}
}
// Updates objects in the main window
void update_screen(void)
{
char cdizi[100];
sprintf(cdizi, "Char height: %d", char_height);
SDL_SetWindowTitle(window, cdizi);
}
// Render function used to draw game objects in the main window
void draw_screen(void)
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // Set the color used for drawing operations.
SDL_RenderClear(renderer); // Clear the current rendering target with the drawing color.
draw_text(50, 50, "www.bilgigunlugum.net");
// Loading all objects drawn one by one to the back buffer to the front buffer at once and loading them onto the screen
// This process prevents each drawn object from being displayed on the screen one by one.
SDL_RenderPresent(renderer); // Update on screen all operations performed since the previous call
}
// Destroy Renderer and SDL window, exit from SDL3
void destroy_window(void)
{
SDL_DestroyTexture(texture_font);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
void draw_text(int x, int y, char* text)
{
char* chars = "abcçdefgğhıijklmnoöpqrsştuüvwxyzABCÇDEFGĞHIİJKLMNOÖPQRSŞTUÜVWXYZ1234567890\"!'^+%&/()=?_#${}[]\\*@~;,`:.|<>-"; // 106 characters
SDL_FRect frect_char = { 0, 0, 0, 110 };
int x_dst = x, y_dst = y;
char *ret;
int char_index;
int width_dst, height_dst;
int rate = 57;
for(int i=0; i<strlen(text); i++) {
height_dst = char_height + (ceil((float)((char_height*rate)/100)));
// Space
if(text[i]==' ') {
x_dst += height_dst/3;
}
// Newline
else if(text[i]=='\n') {
y_dst += height_dst;
x_dst = x;
}
else {
ret = strchr(chars, text[i]);
char_index = ret-chars;
if(char_index<32) frect_char.y = 0;
else if(char_index<64) frect_char.y = 111;
else frect_char.y = 222;
frect_char.x = char_vals[char_index].x;
frect_char.w = char_vals[char_index].w;
width_dst = ceil((float)(char_height * char_vals[char_index].w) / 70);
SDL_FRect rect_dst = { x_dst, y_dst, width_dst, height_dst };
SDL_RenderTexture(renderer, texture_font, &frect_char, &rect_dst);
x_dst += width_dst + 4;
}
}
}