SDL:如何将表面blit到正确使用SDL_CreateRGBSurface创建的表面?

时间:2014-05-05 06:12:42

标签: graphics sdl sdl-image

我试图将IMG_Load(SDL_image)创建的曲面blit到通过SDL_CreateRGBSurface创建的曲面上。当两个曲面都加载IMG_Load时,这样可以正常工作,但不能在使用SDL_CreateRGBSurface创建目标曲面时使用。

通过实验,我发现如果我在源表面上调用SDL_SetAlpha,它会突然正常工作。文档有点缺乏,但我如何理解它,我在下面调用它的方式应该清除SDL_SRCALPHA标志,可能由IMG_Load设置。看起来像 source 表面的alpha标志是blitting时最重要的,所以我想这会完全关闭alpha混合。

最大的问题是:为什么这个SDL_SetAlpha首先是必要的?这真的是正确的方法吗?

以下代码重现了这一点:

#include <SDL/SDL.h>
#include <SDL_image/SDL_image.h>

SDL_Surface* copy_surface(SDL_Surface* source)
{
    SDL_Surface *target;

    target = SDL_CreateRGBSurface(0, source->w, source->h,
                                  source->format->BitsPerPixel,
                                  source->format->Rmask, source->format->Gmask,
                                  source->format->Bmask, source->format->Amask);

    /*
     * I really don't understand why this is necessary. This is supposed to
     * clear the SDL_SRCALPHA flag presumably set by IMG_Load. But why wouldn't
     * blitting work otherwise?
     */
    SDL_SetAlpha(source, 0, 0);

    SDL_BlitSurface(source, 0, target, 0);
    return target;
}

int main(int argc, char* argv[])
{
    SDL_Event event;
    SDL_Surface *copy, *screen, *source;

    SDL_Init(SDL_INIT_VIDEO);
    screen = SDL_SetVideoMode(800, 600, 0, 0);
    SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0xff, 0xff, 0xff));
    source = IMG_Load("source.png");
    if (!source) {
        fprintf(stderr, "Unable to load source image\n");
        return 1;
    }
    copy = copy_surface(source);
    SDL_BlitSurface(copy, 0, screen, 0);
    SDL_Flip(screen);
    while (SDL_WaitEvent(&event))
        if (event.type == SDL_QUIT
            || (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE))
            break;
    SDL_Quit();
    return 0;
}

你需要source.png。我使用400x400透明PNG和一些黑色涂鸦。

1 个答案:

答案 0 :(得分:1)

http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsetalpha.html描述了每种可能的像素格式组合的blitting。

执行Alpha混合时,标准公式为SRC_COLOUR * SRC_ALPHA + DST_COLOUR * (1 - SRC_ALPHA)。目的地alpha不在此处使用。

如果启用了Alpha混合,并且为源曲面启用了SRCALPHA标记,则源alpha将用于重新计算(混合)更新的目标颜色,但目标的Alpha通道保持不变。下次这个&#39; dst&#39;用作blitting的来源,将使用它的alpha。

为了避免您的问题,有几种可能的方法:

  1. 为源表面禁用SRCALPHA(您已尝试过)
  2. 禁用目标曲面的SRCALPHA,因此不会与屏幕混合。它不会影响初始blit,但会影响下一个blit,当你的目标是&#39; (或&#39; copy&#39;)用作屏幕上blit的来源。
  3. 使用不透明的白色填充目标表面。然而,它会影响光斑,在光源的[部分] - 透明部分(与白色和黑色混合的α会产生不同的结果)。
  4. 手动复制像素。如果像素格式和曲面尺寸匹配,仅仅memcpy就足够了。这将覆盖目的地的内容,而不是混合它。它也会明显快于混合。如果尺寸不匹配 - 取决于pitch参数,您可能需要number_of_rows memcpy&#39; s。如果像素格式不匹配 - 复制有问题,则需要从源像素格式解码每个像素并将其编码为目标像素格式。
  5. 使用SDL_ConvertSurface(例如SDL_ConvertSurface(source, source->format, 0)。它会创建具有相同内容的新曲面。我认为这种方式是首选。不要忘记稍后释放新曲面。
  6. 如果您使用SDL 1.2,请使用SDL_DisplayFormatAlpha。这与SDL_ConvertSurface几乎相同,但将表面转换为显示格式,而不是源表面格式。它已不再可用于SDL2。
  7. 另请注意,(4),(5)和(6)只是我看到的方式,允许您保持源alpha。所有blitting操作都会丢弃源alpha,使目标保留其自己的alpha值 - 因为blitting永远不会更新目标alpha。