c++ - 如何使用 C/C++ 和 SDL2 将文件字体加载到 RAM 中?

标签 c++ c sdl-2

根据我学到的“最佳实践”,我们应该将程序所需的资源加载到 RAM 中,避免对用户硬盘驱动器的不必要请求。使用 SDL2,我总是在将图像文件加载到 RAM 后释放它们。 (文件 -> 表面 -> 纹理 -> 免费文件/表面)。因此,如果我的其他应用程序更改了该文件,我的程序将忽略它,因为它不再使用该文件。

现在在第 16 课中,我正在学习使用附加组件 SDL_ttf

但是,使用 SDL_ttf 插件我找不到释放 font.ttf 文件的方法,也无法将其加载到 RAM 中。我只能通过指针看到它。在我看来,每次呈现文本时,文件都会被读取。

我如何将它加载到 RAM 中,以便渲染调用 RAM 位置,而不是 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);}

失败一:

创建一个结构来保存文件中的信息。

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 将文件直接复制到 RAM 中

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

最佳答案

虽然 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 */

关于c++ - 如何使用 C/C++ 和 SDL2 将文件字体加载到 RAM 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55527414/

相关文章:

c - pthreads 传递参数 3 警告

c++ - 将 SDL2 与 CMake 一起使用

c++ - 使用 OpenCV 访问网络摄像机

c++ - 想使用 VOLUME_DISK_EXTENTS 结构

c - 如何正确实现 float 乘法(软件FP)

c - c语言从文件中读取数据

audio - 如何使用 Rust SDL2 播放 WAV 文件?

c - 我在 Xcode 6 上安装 SDL2 时遇到困难

c++ - 为什么我不能删除字符串的数字字符?

c++ - Qt Android 上缺少 QSGContext