Warning: Undefined array key "HTTP_ACCEPT_LANGUAGE" in /var/www/vhosts/bilgigunlugum.net/httpdocs/index.php on line 43
SDL Game Programming

SDL3 Oyun Programlama sayfalarımız yayında...

Ana sayfa > Oyun programlama > SDL3 programming > Image fonts

Image fonts

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:

  1. At the beginning of the program, the following global variables are first defined:
    • SDL_Texture *texture_font: Texture variable
    • int char_height: Char height
    • int image_height: Image height
    • An array named char_vals of the following structure data type is defined:
      struct char_val {
        int x;
        int w;
      } char_vals[CHAR_COUNT];
      
  2. In the init_vars() function,
    • The char_height global variable is assigned an initial value.
    • The x coordinates and width values ​​of the characters in the image file are read from the char_data.bin file and assigned to the char_vals structure array variables.
  3. In the load_img() function, a texture is created for the characters with the IMG_LoadTexture() function.
  4. In the process_event() function, the character size is set between 35-70 with the up and down arrow keys.
  5. In the update_screen() function, the character height is shown in the main window title.
  6. In the draw_screen() function, the character string given with the draw_text() function is written to the main window.

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;
        }
    }
}