【问题标题】:How to embed any *.jpg image inside win32 executable and use it at run time如何在 win32 可执行文件中嵌入任何 *.jpg 图像并在运行时使用它
【发布时间】:2023-03-24 08:02:01
【问题描述】:

我正在做一个名为Space Voyager 的纯OpenGL 和FREEGLUT 项目。问题是在运行期间,当程序调用一个函数来加载所有图像时,播放器必须在加载屏幕上等待大约 2 分钟!!!!有些图像像 16 MB 的文件,否则平均为 1 MB。总共有大约20张图像。我需要在启动关卡之前加载所有图像。

现在我使用SOIL 在我的游戏中加载图像。 SOIL 具有从内存中加载图像的功能 SOIL_load_OGL_texture_load_from_memory( unsigned char *image_in_RAM ,...)。

我的解决方案是将所有图片嵌入到游戏的*.exe 文件中,并在运行时使用,这样可以节省在游戏中加载所有图片的时间。

对于如何将 jpg 图像准确嵌入可执行文件和
,我几乎迷失了方向 在运行时将其用作 unsigned char* imagePointer ?????

【问题讨论】:

  • 您是否对代码进行了分析以检查加载是否是您应用中的瓶颈?
  • 您可以使用 .tga 文件而不是 .jpg 文件?这是一种专为纹理设计的格式。它在您的磁盘上较重,因为文件通常比 .jpg 大,但加载速度稍快。
  • 如果在“exe”文件中,相同的数据会更快地从磁盘加载到内存,逻辑似乎很不稳定。
  • 见 LoadResource 和相关的东西。 msdn.microsoft.com/en-us/library/windows/desktop/…
  • 我看不出这会更快。数据仍然需要从磁盘加载,JPG(或任何格式)仍然需要解码。它只是来自磁盘上的不同位置...

标签: c++ image opengl resources soil


【解决方案1】:

我的解决方案是将所有图片嵌入到游戏的*.exe文件中,并在运行时使用,这样可以节省加载游戏中所有图片的时间。

你认为这会如何解决问题?存储设备上的数据带有什么标签并不重要。计算机系统的工作量是不变的。将资源放在单独的文件中到计算机上都没关系。

有些图片像 16 MB 的文件,否则平均为 1 MB。总共有大约20张图像。我需要在启动关卡之前加载所有图像。

这不是很多数据。平均 1MiB 的 20 张图像,即平均 20MiB。即使是旋转生锈的慢速 HDD 磁盘也可以轻松提供 10MiB/s。如今,更常见的数字是 50MiB 到 80MiB/s 的廉价 HDD。无论您的瓶颈在哪里,都不是 I/O。

另外请记住,如果您将文件 RAW 嵌入到可执行文件中,您会强制系统通过 I/O 推送更多数据;在可执行文件中压缩图像仍然需要您解压缩。鉴于大多数情况下,您需要在存储中存储压缩图像,而不是 CPU 限制。

更新

你的问题是这样的:

SOIL_FLAG_POWER_OF_TWO

您要求土壤将每个图像重新缩放到下一个更大的尺寸,即 2 的幂。在 OpenGL-2 之前必须这样做,因为 OpenGL-1 只接受 2 的幂大小的图像纹理。自从 OpenGL-2 出现(现在你很难找到不支持 OpenGL-2 的 GPU),这个限制就被解除了。

另一个耗时的操作是生成 mipmap (SOIL_FLAG_MIPMAPS),因为这需要为每个图像生成整个图像金字塔。现在 mipmapping 是您通常想要的。如果您的上下文 >=OpenGL-3,您可以使用 OpenGL 内置的 mipmap 生成器。此外,您要求 SOIL 为您生成纹理 ID,但您也自己生成 ID。使用其中之一,但不要同时使用。

这会导致您的代码进行以下建议更改:

while( GL_NO_ERROR != glGetError() ); // flush OpenGL errors;
GLint gl_version;
glGetIntegerv(GL_MAJOR_VERSION, &gl_version);
if( GL_NO_ERROR != glGetError() ) {
    // GL_MAJOR_VERSION enum supported only since OpenGL-3
    gl_version = 1;
    while( GL_NO_ERROR != glGetError() ); // flush OpenGL errors;
}
bool const gl3_or_later = 3 <= gl_version;

tex_id = SOIL_load_OGL_texture(
        fileNameConstant,
        SOIL_LOAD_AUTO,
        SOIL_CREATE_NEW_ID,
        gl3_or_later ? 0 : SOIL_FLAG_MIPMAPS );
if( gl3_or_later ) {
    glBindTexture(GL_TEXTURE_2D, tex_id);
    glGenerateTextureMipmap(GL_TEXTURE_2D);
    glTexParameteri(
        GL_TEXTURE_2D,
        GL_TEXTURE_MIN_FILTER,
        GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(
        GL_TEXTURE_2D,
        GL_TEXTURE_MAX_LEVEL,
        1000);
}

【讨论】:

  • 实际上去所有需要的图像正好是 167 MB。我试图在游戏关卡开始之前加载它们。我需要使用另一个线程来加载资源。希望我可以节省一些花在加载屏幕上的时间。 !!!!谢谢。
  • 我能问你吗,有什么方法可以在运行时加载和链接任何预编译的目标代码。有什么接近的吗??
  • @Sohail_CHD:目标代码有什么关系?是的,您可以将图像数据放入目标代码中,但它的用途是什么。你得到的只是一个结构略有不同的文件,但将图像传输到 GPU 的工作量并没有改变!对电脑来说完全没有区别!您必须在内心深处理解这一点:代码和数据之间没有区别!数据就是代码,代码就是数据。是的,您可以将图像放入 PE 中,然后将 LoadLibrary / dlopen 扔给它,但在幕后它归结为打开和读取文件。
  • @Sohail_CHD: 167MiB 并不是很多数据。即使使用慢速 HDD,也可以在 4 秒内加载。您手头的问题是,SOIL 可能不是最有效的图像加载器。在线生成 mipmap 也很昂贵。如果您预先计算 mipmap,您将获得更多收益。 不要费心尝试以不同的方式打包图像!它不会有任何好处。相反,请查看更高效的 JPEG 加载程序(TurboJPEG、libjpeg-turbo)。内存映射也可以提供帮助,但如果您必须将 while 文件保存在内存中以进行解码,那么简单的读取也可以。
  • 永远学不会这么快。很棒的建议。我将取消 SOIL 并按照您的建议尝试一些东西。维伦丹克!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多