How to load file font into RAM using C/C++ and SDL2?

旧巷老猫 提交于 2019-12-07 14:43:57

问题


Accordingly to the ''best practices'' I have learned, we should load the resources we need to our programs into RAM, avoiding unnecessary requests to user's hard drive. Using SDL2, I always free image files after loading them into RAM. (File -> Surface -> Texture -> Free File/Surface). So, if I other application changes the file, my program ignores it, as the file is not in use by it anymore.

Now in lesson 16 I am learning to use the Add-on SDL_ttf.

However, using SDL_ttf addon I could not find a way to free the font.ttf file, loading it into RAM too. I can only see it through a pointer. It seems to me that the file keeps being read each time I render a text.

How can I load it into RAM, so the rendering calls a RAM position, instead of the file in HD?

Full code

#define SDL_MAIN_HANDLED
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

int G = 255;

int main (void) {SDL_SetMainReady();

    int SCREEN_WIDTH   = 800;
    int SCREEN_HEIGHT  = 600;
    bool QUIT_APPLICATION = false;
    SDL_Event union_Event_manager;

    SDL_Color      str_White_colour = {255,255,255,255};    
    SDL_Window   * ptr_Window       = nullptr;
    SDL_Surface  * ptr_Text_Surface = nullptr;
    SDL_Surface  * ptr_Main_surface = nullptr;
    SDL_RWops    * ptr_str_rwops    = nullptr;
    TTF_Font     * ptr_Font         = nullptr;


    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();


    ptr_Window = SDL_CreateWindow("Lesson 16 - TrueTypeFonts", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
    ptr_Main_surface = SDL_GetWindowSurface(ptr_Window);

    ptr_str_rwops = SDL_RWFromFile("FreeMono.ttf", "r");

    ptr_Font = TTF_OpenFontIndexRW(ptr_str_rwops, 1, 72, 0);

    ptr_Text_Surface = TTF_RenderText_Solid(ptr_Font, "Hello World", str_White_colour);

    while(!QUIT_APPLICATION){

        while(SDL_PollEvent(&union_Event_manager) != 0 ){
            if (union_Event_manager.type == SDL_QUIT) {QUIT_APPLICATION = true;}
        /*END WHILE*/}

    SDL_BlitSurface(ptr_Text_Surface, NULL, ptr_Main_surface, NULL);
    SDL_UpdateWindowSurface(ptr_Window);
    /*END WHILE*/}

    TTF_CloseFont(ptr_Font); 
// if called before any rendering, the app crashes, as supposed to.
// So, how free the **file** and keep using its content from RAM?
    SDL_RWclose(ptr_str_rwops);
    SDL_FreeSurface(ptr_Text_Surface);
    SDL_FreeSurface(ptr_Main_surface);
    SDL_DestroyWindow(ptr_Window);

    ptr_Font         = nullptr;
    ptr_str_rwops    = nullptr;
    ptr_Text_Surface = nullptr;
    ptr_Main_surface = nullptr;
    ptr_Window       = nullptr;

    TTF_Quit();
    SDL_Quit();

return (0);}

Failure 1:

Create a structure to hold information from file.

TTF_Font str_Font; // Error in compilation ''incomplete type''
str_Font = *ptr_Font;
TTF_CloseFont(ptr_Font);
ptr_Font = nullptr;
ptr_Font = &str_Font;   

Reason to failure: I misunderstood how the file works. The structure only holds information about the file, not the media itself. This approach is useless, and crash the program just after freeing the pointer (the rendering tries to dereference a nullptr).

Failure 2:

Use built in function to free resource.

ptr_Font = TTF_OpenFontIndexRW(SDL_RWFromFile("FreeMono.ttf", "r"), 1, 72, 0);

Reason to failure: I do not understand why, as the second argument (non-zero) specifies it should free the resource after usage. It also happens in the completed source code above, where I merely separated the functions in two lines.

Failure 3:

Create structure to hold information about pointer.

ptr_str_rwops = SDL_RWFromFile("FreeMono.ttf", "r");
str_rwops = *ptr_str_rwops;
SDL_RWclose(ptr_str_rwops); // crashes  the program
ptr_str_rwops = nullptr;
ptr_str_rwops = &str_rwops; // useless: file still in use.

Reason to failure: The structure RWops seems to not hold the file, only information about it. So it is the sum of failure 1 and 2.

Failure 4:

Tried to load file as object.

ptr_LoadObject = (TTF_Font*)SDL_LoadObject("FreeMono.ttf");
ptr_str_rwops = SDL_RWFromFile((const char *)ptr_LoadObject, "r");

Reason to failure: This function works with shared operational system files. Wrong usage of function.


Update 2019-04-05

Failure 5

Tried to make a copy of file directly into RAM useing memcpy

long int func_discover_file_size(char* file){

    long int var_file_size = 0;
    FILE * ptr_file = nullptr;

    ptr_file = fopen(file, "rb");
    fseek(ptr_file , 0L , SEEK_END);
    var_file_size = ftell(ptr_file);
    fclose(ptr_file);
    return var_file_size;

/*END func_discover_file_size*/}

int main (void) {

    /*cut unrelated code*/

    void * ptr_load_file = nullptr;
    void * ptr_File_copy = nullptr;
    long int var_file_size = 0;

    /*cut unrelated code*/

    var_file_size = func_discover_file_size("FreeMono.ttf");
    // works fine and returns correct size of file.

    ptr_File_copy = (char*) calloc (1, var_file_size);
    // memory allocation works fine (tested)

    ptr_load_file = fopen("FreeMono.ttf", "rb");
    // file loaded correctly. Test with FOR LOOP shows content of file in console.

    memcpy(ptr_File_copy, ptr_load_file, var_file_size);
    // program crashes in line above

Reason to failure: It looks like I do not know how to correctly use memcpy. I tried many many casts to function and pointers (void, char), tried to change type of pointers to char, void, FILE, tried to output to a third pointer...

Now I am looking for a good soul to enlight my ways... :-p

note: C tagged because SDL


回答1:


While freetype (which SDL_ttf uses) will not read font more than once (which it can't, since its API doesn't provide seek functionality), SDL_ttf will not close file/RWops until font closes. You can achieve what you've described via manually loading file into memory buffer and using that memory as RWops to feed data to SDL_ttf, e.g. (no error checking, no free, etc. - this is just an example):

    /* 'slurp' file (read entire file into memory buffer)
     * there are multiple ways to do so
     */
    SDL_RWops *file_rw = SDL_RWFromFile("font.ttf", "rb");
    Sint64 file_sz = file_rw->size(file_rw);
    void *membuf = malloc(file_sz);
    file_rw->read(file_rw, membuf, 1, file_sz);
    file_rw->close(file_rw);

    /* use memory buffer as RWops */
    SDL_RWops *mem_rw = SDL_RWFromConstMem(membuf, file_sz);
    TTF_Font *font = TTF_OpenFontRW(mem_rw, 1, font_size);

    /* free(membuf) when you're done with the font */



回答2:


The secondary question about memcpy can be solved in the following way:

memcpy copies a file object, not its contents. In order to read from it:

Use fread function to read from FILE*: fread(ptr_File_copy, 1, var_file_size, ptr_load_file) instead of memcpy.



来源:https://stackoverflow.com/questions/55527414/how-to-load-file-font-into-ram-using-c-c-and-sdl2

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!