SDL2 прозрачная поверхность - PullRequest
0 голосов
/ 08 марта 2019

Я пытаюсь создать прозрачную поверхность, поднять ее на большую поверхность (размер моего экрана), затем создать ее текстуру, скопировать в средство визуализации и, наконец, отобразить подарок.

Я видел много других форумов, которые говорили, что я должен использовать SetBlendMode (для поверхности, текстуры и рендерера), ColorKey, SetSurfaceBlendMode. Я попробовал их все, но я не могу заставить его работать. Я читал, что SDL_BlitScaled не подходит для объединения поверхностей с прозрачными пикселями, но я полностью растерялся относительно того, что я должен делать вместо этого.

Что я заметил, когда я использую SDL_CreateRGBSurface (с альфа-значением) для создания поверхности, PixelFormat поверхности - это RGB888 вместо RGBA8888 (что я и ожидал, поскольку я предоставляю альфа-значение). Использование SDL_ConvertSurfaceFormat не помогло.

Может кто-нибудь сказать мне, что мне не хватает?

Полный код: удалено, мои извинения

Обратите внимание, что я удалил попытки заставить работать прозрачность

Рендерер:

mRenderer = SDL_CreateRenderer(mWindow, -1, SDL_RENDERER_ACCELERATED);

Мой цикл рендеринга:

void CApp::Render()
{
    SDL_RenderClear(mRenderer);

    mBackGround->Render(mRenderer);
    mForeGround->Render(mRenderer);

    SDL_RenderPresent(mRenderer);
}

Большая поверхность, на которую я бьюсь:

mSurface = SDL_CreateRGBSurface(0, CApp::Window_W(), CApp::Window_H(), 32, 0, 0, 0, 0);

Код для получения плиток из таблицы спрайтов:

bool Map::GetTilesFromSpriteSheet(SDL_Surface *pSpriteSheet, int pTile_w, int pTile_h)
{
    if(pSpriteSheet->w % pTile_w == 0 && pSpriteSheet->h % pTile_h == 0) {
        SDL_Rect srcRect;
        srcRect.w = pTile_w;
        srcRect.h = pTile_h;
        for(int y = 0; y < pSpriteSheet->h / pTile_h; y++) {
            for(int x = 0; x < pSpriteSheet->w / pTile_w; x++) {
                srcRect.x = x*pTile_w;
                srcRect.y = y*pTile_h;
                SDL_Surface* tempSurface = SDL_CreateRGBSurface(0, pTile_w, pTile_h, 32, 0, 0, 0, 0);
                if(SDL_BlitSurface(pSpriteSheet, &srcRect, tempSurface, nullptr)==0) {
                    mTiles.push_back(tempSurface);
                } else {
                    Log("Error extracting tile (%d,%d)(w,h): %s", x, y, SDL_GetError());
                    return false;
                }
            }
        }
        Log("Number of tiles: %d", static_cast<int>(mTiles.size()));
    } else {
        Log("Background spritesheet is incompatible with tile dimensions (%d,%d)(w,h).", pTile_w, pTile_h);
        return false;
    }
    return true;
}

Здесь я объединяю плитки, чтобы создать большую поверхность:

bool Map::GenerateMap(std::vector<std::vector<int>> &pMap, std::vector<SDL_Surface*> &pTiles, SDL_Surface* pDestination)
{
    SDL_Rect rect;
    rect.w = mDstTile_W;
    rect.h = mDstTile_H;
    SDL_Surface* transparent = SDL_CreateRGBSurface(0, mDstTile_W, mDstTile_H, 32, 0, 0, 0, 0);

    for(int y = 0; y < static_cast<int>(pMap.size()); y++) {
        for(int x = 0; x < static_cast<int>(pMap.at(static_cast<unsigned long>(y)).size()); x++) {
            rect.x = x*mDstTile_W;
            rect.y = y*mDstTile_H;
            int index = static_cast<int>(pMap.at(static_cast<unsigned long>(y)).at(static_cast<unsigned long>(x)));
            if(index < 0) {
                if(SDL_BlitScaled(transparent, nullptr, pDestination, &rect) != 0) {
                    Log("Error blitting transparent surface to destination: %s", SDL_GetError());
                }
            } else if(SDL_BlitScaled(pTiles[static_cast<unsigned long>(index)],
                              nullptr, pDestination, &rect) != 0) {
                Log("Error blitting surface to destination: %s", SDL_GetError());
                return false;
            }
        }
    }
    SDL_FreeSurface(transparent);
    return true;
}

И наконец, это код для рендеринга большой поверхности на экране, сначала путем создания текстуры:

void ForeGround::Render(SDL_Renderer* pRenderer)
{
    if(mTexture) SDL_DestroyTexture(mTexture);
    mTexture = SDL_CreateTextureFromSurface(pRenderer, mSurface);

    if(mTexture == nullptr) {
        Log("Unable to create foreground texture: %s", SDL_GetError());
    } else if (SDL_RenderCopy(pRenderer, mTexture, nullptr, nullptr)) {
        Log("Unable to render foreground: %s", SDL_GetError());
    }
}

1 Ответ

0 голосов
/ 09 марта 2019

Как уже упоминалось @keltar, я не создавал поверхности с альфа-значением.

Я должен был изменить вызов SDL_CreateRGBSurface. Приведенный ниже фрагмент кода создает пустую прозрачную поверхность, на которую я могу при необходимости перетаскивать (например, плитки из таблицы спрайтов).

SDL_Surface* tempSurface = SDL_CreateRGBSurface(..., 32, 0xff, 0xff00, 0xff0000, 0xff000000);

Приведенный ниже фрагмент кода создает черную непрозрачную поверхность.

SDL_Surface* tempSurface = SDL_CreateRGBSurface(..., 32, 0xff, 0xff00, 0xff0000, 0x00000000);

Мне этого было достаточно, я не должен был использовать SDL_SetRenderDrawBlendMode, SDL_SetSurfaceBlendMode, SDL_SetTextureBlendMode или SDL_ConvertSurface. Быстрый просмотр SDL вики показал:

По умолчанию поверхности с альфа-маской настроены для смешивания как с

SDL_SetSurfaceBlendMode (поверхность, SDL_BLENDMODE_BLEND)

Что объясняет, почему мне не пришлось вызывать ни одну из этих функций. Большой привет Келтару за его быстрый ответ!

...