【问题标题】:How to create one bitmap from parts of many textures (C++, SDL 2)?如何从许多纹理的一部分(C++、SDL 2)创建一个位图?
【发布时间】:2013-11-17 21:38:40
【问题描述】:

我有 *.png 文件,我想从纹理中获取不同的 8x8 像素部分并将它们放置在位图上(我猜是 SDL_Surface,但可能不是),就像这样:

现在我在没有位图的情况下渲染它,即我调用每个纹理并在每一帧直接在屏幕上绘制部分,它太慢了。我想我需要加载每个 *.png 来分隔位图并使用它们传递视频内存,然后只调用一个大位图,但也许我错了。我需要最快的方法,我需要这样的代码(SDL 2,而不是 SDL 1.3)。 另外,也许我需要在这里使用清晰的 OpenGL?

更新:
或者我可能需要以某种方式将 *.png 加载到 int 数组中,并像通常的数字一样使用它们并将它们放置到一个大的 int 数组中,然后将其转换为 SDL_Surface/SDL_Texture?这似乎是最好的方法,但是如何写呢?

更新 2:
每个块中像素的颜色与图片中呈现的颜色不同,也可以是透明的。图片只是一个例子。

【问题讨论】:

  • 8x8 像素的部分都是纯色的吗?如果是,你有固定数量的颜色吗?我认为您可能需要某种地图来表示您从 .png 部分构建的纹理中的所有单元格。你可以使用二维数组。
  • 注意。在 SDL2 中将 SDL_Textures 渲染到屏幕实际上应该非常快(与渲染 SDL_Surfaces SDL 1.2 相比)。我认为单个 8x8px 部分的渲染可能不是让事情变慢的原因——它可能是你正在做的检查数量导致了瓶颈。渲染到单个自定义纹理然后渲染 that 不太可能显着加快速度。你能做任何时间测试来找出是什么让它变慢了吗?
  • 你是什么意思“坚实”?颜色可以是透明的,RGBA。现在我使用this。我制作数组并将其发送到地面,这部分速度为 100 FPS,足够快。但是SDL_UpdateTexture函数很慢(顺便说在文档中),所以我想在这个地方清除OpenGL...
  • @Necronomicon,请看下面我的回答。

标签: c++ bitmap sdl pixel sdl-2


【解决方案1】:

假设您已经将位图加载为 SDL_Texture(s),则通过 SDL_SetRenderTarget 将它们组合成不同的纹理。

SDL_SetRenderTarget(renderer, target_texture);
SDL_RenderCopy(renderer, texture1, ...);
SDL_RenderCopy(renderer, texture2, ...);
...
SDL_SetRenderTarget(renderer, NULL);

您在设置渲染目标和重置它(通过使用 NULL 纹理参数调用 SDL_SetRenderTarget)之间执行的每个渲染操作都将渲染到指定的纹理。然后,您可以像使用任何其他纹理一样使用此纹理。

【讨论】:

  • 但是纹理的顺序是随机的,所以我需要检查是否在当前单元格中绘制这个纹理,然后是下一个纹理,所以检查太多了。
【解决方案2】:

好吧,当我问及“纯色”时,我的意思是 -“在您从中复制的 .png 中的 8x8 像素区域中,所有 64 像素是否具有相同的 RGB 值?”它在你的图表中看起来是这样的,那么这个怎么样:

如何创建一个SDL_Surface,并使用从原始.png 读取的值直接绘制该SDL_Surfacepixels 成员指向的内存的8x8 像素区域。

然后当你完成后,将该表面转换为SDL_Texture 并渲染那个

您将避免所有SDL_UpdateTexture() 调用。

无论如何,这里有一些示例代码。假设您创建了一个名为EightByEight 的类。

  class EightByEight
  {
    public:
      EightByEight( SDL_Surface * pDest, Uint8 r, Uint8 g, Uint8 b):
          m_pSurface(pDest),
          m_red(r),
          m_green(g),
          m_blue(b){}

      void BlitToSurface( int column, int row );

    private:
      SDL_Surface * m_pSurface;
      Uint8 m_red;
      Uint8 m_green;
      Uint8 m_blue;
  };

你可以构造一个EightByEight 类型的对象,方法是传递一个指向SDL_Surface 的指针以及一些红色、绿色和蓝色的值。此 RGB 对应于从您当前正在读取的 .png 的特定 8x8 像素区域获取的 RGB 值。您将使用此 RGB 值绘制 SDL_Surface 像素的特定 8x8 像素区域。

所以现在当你想绘制SDL_Surface 的一个区域时,你可以使用函数BlitToSurface() 并传入一个列和行值。例如,如果您将SDL_Surface 划分为 8x8 像素的正方形,BlitToSurface(3,5) 表示使用我在构造时设置的 RGB 值在第 4 列和第 5 行绘制正方形。

BlitToSurface() 看起来像这样:

void EightByEight::BlitToSurface(int column, int row)
{
  Uint32 * pixel = (Uint32*)m_pSurface->pixels+(row*(m_pSurface->pitch/4))+column;

  // now pixel is pointing to the first pixel in the correct 8x8 pixel square 
  // of the Surface's pixel memory. Now you need to paint a 8 rows of 8 pixels, 
  // but be careful - you need to add m_pSurface->pitch - 8 each time 

  for(int y = 0; y < 8; y++)
  {
      // paint a row
      for(int i = 0; i < 8; i++)
      {
        *pixel++ = SDL_MapRGB(m_pSurface->format, m_red, m_green, m_blue);
      }

      // advance pixel pointer by pitch-8, to get the next "row".
      pixel += (m_pSurface->pitch - 8);
   }
}

我相信您可以通过预先计算构建时的 RGB 值来进一步加快速度。或者,如果您正在从纹理中读取像素,您可能会省去 SDL_MapRGB()(但它只是在 Surface 与 .png 具有不同像素格式的情况下存在)。

memcpy 可能比对 RGB 值的 8 个单独分配要快 - 但我只是想演示该技术。你可以做实验。

因此,您创建的所有EightByEight 对象都指向同一个SDL_Surface

然后,当你完成后,你只需将 SDL_Surface 转换为 SDL_Texture 并 blit 即可。

【讨论】:

  • "所有 64 个像素的 RGB 值是否相同?"啊,不,这张图只是一个例子,一个块有不同的颜色。如果您了解泰拉瑞亚游戏,请想象一下任何事情。
  • “然后当你完成后,将该表面转换为 SDL_Texture 并渲染它?”在我开始使用 SDL_UpdateTexture 之前我也这样做过,也太慢了。
  • 我完全使用memcpy 制作我的数组。正如我所说,计算非常快,延迟是从SDL_SurfaceSDL_Texture 的转换。我尝试了不同的变体,看来我必须在这部分使用干净的 OpenGL。
【解决方案3】:

感谢所有参与的人,但我们和朋友一起解决了这个问题。所以这里举个例子(源代码太大,这里没必要,我只描述主要思想):

int pitch, *pixels;
SDL_Texture *texture;
...
if (!SDL_LockTexture(texture, 0, (void **)&pixels, &pitch))
{
    for (/*Conditions*/)
        memcpy(/*Params*/);
    SDL_UnlockTexture(texture);
}
SDL_RenderCopy(renderer, texture, 0, 0);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多