我需要尽可能高效地在旧的基于 CD 的游戏控制台上加载大型模型和其他结构化二进制数据。最好的方法是什么?数据将从 Python 应用程序导出。这是一个非常复杂的爱好项目。

要求:

  • 不依赖完全符合标准的 STL - 不过我可能会使用 uSTL。
  • 尽可能少的开销。寻求一个很好的解决方案。它可以在原来的 Playstation 上使用,但又尽可能现代和优雅。
  • 无需向后/向前兼容性。
  • 不复制大块 - 最好将文件在后台加载到 RAM 中,然后直接从那里访问所有大块。
  • 不应依赖具有相同字节序和对齐方式的目标,即Python 中的 C 插件将其结构转储到光盘并不是一个好主意。
  • 应该允许移动加载的数据,就像 RAM 大小 1/3 的单个文件一样,碎片可能是一个问题。没有 MMU 可以滥用。
  • 鲁棒性是一个很大的好处,因为我的注意力持续时间很短,即我会更改保存部分代码并忘记加载代码,反之亦然,所以至少有一个愚蠢的保护措施会很好。
  • 加载的数据和运行时生成的数据之间的可交换性,没有运行时开销,也没有严重的内存管理问题,将是一个很好的好处。

我有一个在 Python 中解析简单的、有限语法的 C 标头的半计划,它将使用带有偏移量的结构而不是指针,以及主应用程序中带有 getters 的方便包装器结构/类,它将偏移量转换为正确类型的指针/参考资料,但我想听听你的建议。

澄清:该请求主要涉及数据加载框架和内存管理问题。

有帮助吗?

解决方案

这是常见的游戏开发模式。

通常的方法是在离线预处理步骤中烘焙数据。生成的 blob 可以以最小的开销流入。Blob 与平台相关,并且应包含目标平台的正确对齐方式和字节序。

在运行时,您可以简单地将指针转换为内存中的 blob 文件。您也可以处理嵌套结构。如果您保留一个内容表,其中包含 blob 中所有指针值的偏移量,则可以修复指针以指向正确的地址。这与 dll 加载的工作原理类似。

我一直在开发一个红宝石库, 烧烤, ,我用它来为我的 iPhone 游戏制作数据。

这是我用于 blob 标头的内存布局:

// Memory layout
//
// p begining of file in memory.
// p + 0 : num_pointers
// p + 4 : offset 0
// p + 8 : offset 1
// ...
// p + ((num_pointers - 1) * 4) : offset n-1
// p + (num_pointers * 4) : num_pointers   // again so we can figure out 
//                                            what memory to free.
// p + ((num_pointers + 1) * 4) : start of cooked data
//

以下是我加载二进制 blob 文件并修复指针的方法:

void* bbq_load(const char* filename)
{
    unsigned char* p;
    int size = LoadFileToMemory(filename, &p);
    if(size <= 0)
        return 0;

    // get the start of the pointer table
    unsigned int* ptr_table = (unsigned int*)p;
    unsigned int num_ptrs = *ptr_table;
    ptr_table++;

    // get the start of the actual data
    // the 2 is to skip past both num_pointer values
    unsigned char* base = p + ((num_ptrs + 2) * sizeof(unsigned int));

    // fix up the pointers
    while ((ptr_table + 1) < (unsigned int*)base)
    {
        unsigned int* ptr = (unsigned int*)(base + *ptr_table);
        *ptr = (unsigned int)((unsigned char*)ptr + *ptr);
        ptr_table++;
    }

    return base;
}

我的 烧烤 库还没有完全准备好迎接黄金时段,但它可以给你一些关于如何用 python 自己编写一个库的想法。

祝你好运!

其他提示

在 Nintendo GameCube 和 DS 等平台上,3D 模型通常以非常简单的自定义格式存储:

  • 一个简短的标头,包含标识文件的幻数、顶点数、法线等,以及可选的标头后面数据的校验和(Adler-32、CRC-16 等)。
  • 每个向量和法线的 32 位浮点三元组的可能压缩列表。
  • 可能压缩的边或面列表。
  • 所有数据均采用目标平台的本机字节序格式。
  • 压缩格式通常是简单的(霍夫曼)、简单的(算术)或标准的(gzip)。所有这些都需要很少的内存或计算能力。

您可以将这样的格式作为提示:这是一个相当紧凑的表示。

我的建议是使用与内存中数据结构最相似的格式,以最大限度地减少后处理和复制。如果这意味着您自己创建格式,那就这样吧。你有极端的需求,所以需要采取极端的措施。

我注意到您的描述中没有任何地方要求“易于编程”。:-)

因此,我想到的创建此内容的方法如下:

  • 数据在磁盘上的格式应与目标内存中的格式相同,这样它就可以简单地将 blob 从磁盘提取到内存中,而无需重新格式化。根据您想要将内容放入内存的自由度,“blob”可以是整个文件,也可以是其中较小的部分;我不太了解您的数据,无法建议如何细分它,但想必您可以。因为我们不能依赖主机上相同的字节序和对齐方式,所以在主机端编写文件时,您需要巧妙地翻译内容,但至少这样您只需要一方面的聪明转移而不是两者都转移。

  • 为了保证目标端和主机端代码匹配,您应该以提供单个数据描述的形式编写此代码,并使用一些生成代码来生成目标端 C 代码和来自其中的主机端 Python 代码。您甚至可以让生成器在此过程中生成一个小的随机“版本”号,并让主机端代码将其写入文件头,然后目标端检查它,如果它们不匹配,则给出错误。(使用随机值的要点是,您关心的唯一信息位是它们是否匹配,并且您不想手动增加它。)

考虑将数据作为 BLOB 存储在 SQLite DB 中。SQLite 非常可移植且轻量级,ANSI C,具有 C++ 和 Python 接口。这将处理大文件、无碎片、具有快速访问的可变长度记录等。剩下的只是将结构序列化为这些 BLOB。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top