如何使用 C/C++ 和 SDL2 将文件字体加载到 RAM 中? [英] How to load file font into RAM using C/C++ and SDL2?

查看:52
本文介绍了如何使用 C/C++ 和 SDL2 将文件字体加载到 RAM 中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

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

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

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

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.

如何将其加载到 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);}

失败 1:

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

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;   

失败的原因:我误解了文件的工作原理.该结构仅包含有关文件的信息,而不包含媒体本身.这种方法是无用的,并且在释放指针后立即崩溃程序(渲染尝试取消引用 nullptr).

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).

使用内置函数释放资源.

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.

创建结构以保存有关指针的信息.

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.

失败的原因:RWops 结构似乎不保存文件,只保存有关它的信息.所以它是失败 1 和 2 的总和.

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.

尝试将文件作为对象加载.

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.

更新 2019-04-05

Update 2019-04-05

尝试使用 memcpy 将文件副本直接复制到 RAM 中

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

失败的原因:看起来我不知道如何正确使用 memcpy.我尝试了许多对函数和指针(void,char)的转换,尝试将指针类型更改为 char,void,FILE,尝试输出到第三个指针...

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...

现在我正在寻找一个好的灵魂来照亮我的道路...... :-p

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

注意:C 标记是因为 SDL

推荐答案

虽然 freetype(SDL_ttf 使用的)不会多次读取字体(它不能,因为它的 API 不提供 seek 功能),SDL_ttf 在字体关闭之前不会关闭文件/RWops.您可以通过手动将文件加载到内存缓冲区并使用该内存作为 RWops 将数据提供给 SDL_ttf 来实现您所描述的,例如(没有错误检查,没有免费等 - 这只是一个例子):

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

这篇关于如何使用 C/C++ 和 SDL2 将文件字体加载到 RAM 中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆