SDL + SDL_ttf: прозрачный смешанный текст?

Я хочу отобразить сглаженную строку на SDL_Surface с заданным альфа-каналом.

Я понял, что можно сделать:

  • сглаженная строка с вариантом Blended метода рендеринга строки (то есть: TTR_RenderText_Blended). Но тогда я не могу сделать его прозрачным.
  • Сглаженная строка с методом Shaded. Зато есть солидный фон. Фон и нарисованную строку можно сделать прозрачными, но тогда останется сплошной фон. Передача ему прозрачного цвета фона также невозможна.
  • строка без сглаживания, которую я могу сделать прозрачной, как я хочу, с вариантом Solid. Но это не сглаживание.

Спасибо


person Martijn Courteaux    schedule 12.07.2010    source источник
comment
Вы когда-нибудь заставляли это работать?   -  person Malabarba    schedule 21.10.2011
comment
@BruceConnor: Нет. Это действительно очень грустно. Что я сделал, так это перешел на OpenGL и использовал растровый шрифт. Это требует много работы, но когда я, наконец, заработал, я был очень доволен. Надеюсь, вы готовы потратить несколько часов на программирование, чтобы сделать то же самое.   -  person Martijn Courteaux    schedule 21.10.2011
comment
Добрый день, у меня такая же проблема как и у вас, так и не решил. Возможно, у вас уже есть идея, я задал там вопрос: stackoverflow.com/questions/12700085. В моем случае я пока не могу использовать растровый шрифт.   -  person ForceMagic    schedule 03.10.2012
comment
@ForceMagic: Нет, я никогда не решал эту проблему. Я перешел к реальным вещам, которые работают с GPU, а не с CPU. Изучите OpenGL, он намного мощнее. Как только вы узнаете, как его использовать, вы будете рады, что научились.   -  person Martijn Courteaux    schedule 03.10.2012
comment
@MartijnCourteaux Спасибо за совет, в настоящее время я использую оба варианта, я использую SDL, чтобы облегчить себе жизнь с помощью ввода с помощью мыши и тому подобного, но я использую OpenGL для рисования большинства моих текстур и системы плиток на экране. Однако я подумал, что SDL_ttf может сэкономить мне время на части рисования текста. В основном я пытался нарисовать сгенерированную текстуру из SDL_ttf с помощью OpenGL. Однако их сочетание не кажется очень эффективным.   -  person ForceMagic    schedule 03.10.2012
comment
@ForceMagic: Нет, действительно. Не рекомендуется рисовать поверх буфера OpenGL с помощью SDL. Используйте растровые шрифты, заставить их работать очень сложно, но они довольно быстрые (намного быстрее, чем SDL_ttf).   -  person Martijn Courteaux    schedule 03.10.2012
comment
Напротив, я думаю, что SDL_ttf отлично работает с OpenGL. Если у вас есть функция для преобразования поверхности в текстуру GL, вы можете без проблем визуализировать ее на квадроцикле (с альфа-смешиванием). На самом деле нет никакой разницы между TTF- и растровым шрифтом, если они хранятся в текстурах.   -  person Daniel Hanrahan    schedule 08.10.2012


Ответы (4)


Почему бы не использовать растровые шрифты? Вы можете создать изображение png с альфа-каналом. Я думаю, что SDL_ttf работает с той же системой, он строит изображение, внутри которого используются растровые шрифты.

person Victor Marzo    schedule 19.07.2010
comment
Обратите внимание, что @ForceMagic удалил неработающую ссылку. Если вы можете найти замену, пожалуйста, добавьте ее обратно. Для ForceMagic, поскольку вы просили, удалить неработающую ссылку можно, но, пожалуйста, добавьте комментарий (который уведомит автора), чтобы они могли получить уведомление и найти новую ( или замена) ссылка. - person Servy; 03.10.2012

Я знаю, что немного опоздал с этим :/

Согласно документации SDL на SDL_SetAlpha:

Обратите внимание, что альфа-канал для каждого пикселя и альфа-канал для каждой поверхности не могут быть объединены; всегда используется попиксельная альфа-канал, если она доступна.

Так что обычные SDL_BlitSurface/SDL_SetAlpha здесь не подойдут. Но это может быть сделано:

Пример использования только SDL

Единственные способы, которыми я могу думать об альфа-смешении TTF_RenderText_Blended вывода, - это использовать OpenGL или настроить альфа-значения каждого пикселя на поверхности.

Регулируя значения альфа-канала для каждого пикселя

Вы можете сделать это, масштабируя значения альфа-канала для каждого пикселя от [0, 255] до нового диапазона [0, alpha]:

// Changes a surface's alpha value, by altering per-pixel alpha if necessary.
void SetSurfaceAlpha (SDL_Surface *surface, Uint8 alpha)
{
    SDL_PixelFormat* fmt = surface->format;

    // If surface has no alpha channel, just set the surface alpha.
    if( fmt->Amask == 0 ) {
        SDL_SetAlpha( surface, SDL_SRCALPHA, alpha );
    }
    // Else change the alpha of each pixel.
    else {
        unsigned bpp = fmt->BytesPerPixel;
        // Scaling factor to clamp alpha to [0, alpha].
        float scale = alpha / 255.0f;

        SDL_LockSurface(surface);

        for (int y = 0; y < surface->h; ++y) 
        for (int x = 0; x < surface->w; ++x) {
            // Get a pointer to the current pixel.
            Uint32* pixel_ptr = (Uint32 *)( 
                    (Uint8 *)surface->pixels
                    + y * surface->pitch
                    + x * bpp
                    );

            // Get the old pixel components.
            Uint8 r, g, b, a;
            SDL_GetRGBA( *pixel_ptr, fmt, &r, &g, &b, &a );

            // Set the pixel with the new alpha.
            *pixel_ptr = SDL_MapRGBA( fmt, r, g, b, scale * a );
        }   

        SDL_UnlockSurface(surface);
    }       
}           

Я знаю, это выглядит пугающе, но это довольно прямолинейно. Ключевая строка здесь:

*pixel_ptr = SDL_MapRGBA( fmt, r, g, b, scale * a );

Вы можете использовать его следующим образом:

text_surface = TTF_RenderText_Blended( font, "Hello World!", color );
SetSurfaceAlpha( text_surface, 128 );

С OpenGL

Если вы используете OpenGL, все намного проще. Предполагая, что вы конвертируете SDL_Surface из TTF_RenderText_Blended в текстуру GL, вы можете просто использовать:

glColor4f( 1.0, 1.0, 1.0, Alpha );

перед визуализацией на текстурированном четырехугольнике.

Но не забудьте сначала включить альфа-смешивание!

glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
person Daniel Hanrahan    schedule 07.10.2012
comment
Спасибо, что нашли время, чтобы предоставить этот поздний ответ. Вы можете получить с ним значок Некроманта, когда за него проголосует еще несколько человек. - person ypnos; 08.10.2012
comment
Кроме того, если вы используете программируемый конвейер OpenGL, в фрагментном шейдере вы можете умножить единицу текстуры на альфа-значение. цвет = мой цвет.a * текстура (моя текстура, мои координаты); - person JoshBramlett; 30.04.2016

Все, что вам нужно сделать, это вызвать SDL_SetAlpha на вашем SDL_Surface после создание спрайта, на котором отображается текст, но перед вызовом SDL_DisplayFormatAlpha для этого спрайта.

// Make the sprite with the text on it
SDL_Surface *swSprite = TTF_RenderText_Solid( font, text, textColor ) ;

// CALL SET ALPHA NOW
SDL_SetAlpha( swSprite, SDL_SRCALPHA, 128 ) ; // 50% opacity

// OK, NOW you can convert it to display format.  I'm presuming
// you called `SDL_SetVideoMode` with the `SDL_HWSURFACE` flag set previously
SDL_Surface* hwSprite = SDL_DisplayFormatAlpha( swSprite ) ;

// If you invert the above 2 steps, it won't work.

// We don't need the software sprite anymore
SDL_FreeSurface( swSprite ) ;

// Now draw the hwSprite as normal
SDL_BlitSurface( hwSprite, NULL, screen, &spriteLocation );
person bobobobo    schedule 26.12.2012
comment
Обратите внимание, что это будет работать только с вариантом TTF_RenderText_Solid, а не с TTF_RenderText_Blended. - person Daniel Hanrahan; 11.11.2014

Способ сделать это с помощью TTF — использовать SDL_SetTextureAlphaMod() Что-то вроде этого

SDL_Surface *surface;
SDL_Texture *texture;
SDL_Color color = {255, 255, 255, 128}
surface = TTF_RenderText_Blended_Wrapped(myFont, "HI!", color, 100);
// myFont and the _renderer is pre-defined somewhere in the game
texture = SDL_CreateTextureFromSurface(_renderer, surface);
SDL_SetTextureAlphaMod(texture, color.a);
SDL_RenderCopy(_renderer, texture, NULL, &dest);
SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);

/*...*/

SDL_RenderPresent(_renderer);

https://wiki.libsdl.org/SDL_SetTextureAlphaMod

person Lord Wolfenstein    schedule 11.03.2018
comment
ура, спасибо за ответ! Интересно, это новое, так как вопрос был изначально опубликован? Но это определенно сработало для меня. +1 - person NHDaly; 20.08.2018