Как загрузить файл шрифта в оперативную память, используя C / C ++ и SDL2? - PullRequest
3 голосов
/ 05 апреля 2019

В соответствии с «лучшими практиками», которые я изучил, мы должны загружать ресурсы, необходимые для наших программ, в оперативную память, избегая ненужных запросов на жесткий диск пользователя. Используя SDL2, я всегда освобождаю файлы изображений после загрузки их в оперативную память. (Файл -> Поверхность -> Текстура -> Свободный файл / Поверхность). Поэтому, если я изменяю файл другим приложением, моя программа игнорирует его, поскольку файл больше не используется им.

Теперь в уроке 16 я учусь пользоваться дополнением SDL_ttf.

Однако, используя SDL_ttf addon, я не смог найти способ освободить файл font.ttf и загрузить его в оперативную память. Я могу видеть это только через указатель. Мне кажется, что файл продолжает читаться каждый раз, когда я отрисовываю текст.

Как я могу загрузить его в ОЗУ, чтобы рендеринг вызывал позицию ОЗУ вместо файла в HD?

Полный код

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

Ошибка 1:

Создать структуру для хранения информации из файла.

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

Причина отказа: Я неправильно понял, как работает файл. Структура содержит только информацию о файле, но не сам носитель. Этот подход бесполезен и приводит к аварийному завершению работы программы сразу после освобождения указателя (рендеринг пытается разыменовать nullptr).

Ошибка 2:

Используйте встроенную функцию для освобождения ресурса.

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

Причина отказа: Я не понимаю, почему, поскольку второй аргумент (ненулевой) указывает, что он должен освободить ресурс после использования. Это также происходит в приведенном выше исходном коде, где я просто разделил функции на две строки.

Ошибка 3:

Создать структуру для хранения информации об указателе.

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.

Причина отказа: Структура RWops, похоже, не содержит файл, а только информацию о нем. Так что это сумма ошибок 1 и 2.

Ошибка 4:

Пытался загрузить файл как объект.

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

Причина отказа: Эта функция работает с общими файлами операционной системы. Неправильное использование функции.


Обновление 2019-04-05

Отказ 5

Пытался сделать копию файла прямо в ОЗУ, используя 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

Причина отказа: Похоже, я не знаю, как правильно использовать memcpy. Я перепробовал множество приведений для работы и указателей (void, char), попытался изменить тип указателей на char, void, FILE, попытался вывести на третий указатель ...

Теперь я ищу хорошую душу, чтобы осветить мои пути ...: -p

примечание: C помечен, потому что SDL

Ответы [ 2 ]

2 голосов
/ 05 апреля 2019

Хотя freetype (который использует SDL_ttf) не будет читать шрифт более одного раза (что не может, поскольку его API не обеспечивает функциональность seek), SDL_ttf не будет закрывать файл / RWops, пока шрифт не закроется.Вы можете достичь того, что вы описали, вручную загрузив файл в буфер памяти и используя эту память в качестве RWops для подачи данных в SDL_ttf, например (без проверки ошибок, без освобождения и т. Д. - это всего лишь пример):

    /* '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 */
0 голосов
/ 06 апреля 2019

Вторичный вопрос о memcpy может быть решен следующим образом:

memcpy копирует объект файла, а не его содержимое.Для чтения из него:

Используйте функцию fread для чтения из FILE*: fread(ptr_File_copy, 1, var_file_size, ptr_load_file) вместо memcpy.

...