使用SDL_ttf和OpenGL,TTF_RenderUTF8_Blended打印红色矩形。

4
当我使用TTF_RenderUTF8_Blended来渲染文本时,屏幕上会出现一个实心矩形。颜色取决于我选择的颜色,我的情况下矩形是红色。 Result using TTF_RenderUTF8_Blended

我的问题

我错过了什么?似乎我没有从使用SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended(...))生成的表面中获得正确的Alpha值,或者我有吗?有人认识或知道这个问题吗?

附加信息

如果我使用TTF_RenderUTF8_SolidTTF_RenderUTF8_Shaded,则文本将被正确绘制,但当然不会混合。
我还在屏幕上绘制其他纹理,所以我最后绘制文本,以确保混合将考虑当前表面。 编辑:SDL_Color g_textColor = {255, 0, 0, 0}; <-- 我尝试使用和不使用alpha值,但结果相同。
我已经尝试总结代码而不删除太多细节。以"g_"为前缀的变量是全局变量。

Init()函数

// This function creates the required texture.
bool Init()
{
    // ...

    g_pFont = TTF_OpenFont("../arial.ttf", 12);
    if(g_pFont == NULL)
        return false;

    // Write text to surface
    g_pText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended(g_pFont, "My first Text!", g_textColor)); //< Doesn't work

    // Note that Solid and Shaded Does work properly if I uncomment them.
    //g_pText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Solid(g_pFont, "My first Text!", g_textColor));
    //g_pText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Shaded(g_pFont, "My first Text!", g_textColor, g_bgColor));

    if(g_pText == NULL)
        return false;

    // Prepare the texture for the font
    GLenum textFormat;
    if(g_pText->format->BytesPerPixel == 4)
    {
        // alpha
        if(g_pText->format->Rmask == 0x000000ff)
            textFormat = GL_RGBA;
        else
            textFormat = GL_BGRA_EXT;
    }

    // Create the font's texture
    glGenTextures(1, &g_FontTextureId);
    glBindTexture(GL_TEXTURE_2D, g_FontTextureId);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, g_pText->format->BytesPerPixel, g_pText->w, g_pText->h, 0, textFormat, GL_UNSIGNED_BYTE, g_pText->pixels);

    // ...
}

DrawText() function

// this function is called each frame
void DrawText()
{
    SDL_Rect sourceRect;
    sourceRect.x = 0;
    sourceRect.y = 0;
    sourceRect.h = 10;
    sourceRect.w = 173;

    // DestRect is null so the rect is drawn at 0,0
    SDL_BlitSurface(g_pText, &sourceRect, g_pSurfaceDisplay, NULL);

    glBindTexture(GL_TEXTURE_2D, g_FontTextureId);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBegin( GL_QUADS );

        glTexCoord2f(0.0f, 0.0f);
        glVertex2f(0.0f, 0.0f);

        glTexCoord2f(0.0f, 1.0f);
        glVertex2f(0.0f, 10.0f);

        glTexCoord2f(1.0f, 1.0f);
        glVertex2f(173.0f, 10.0f);

        glTexCoord2f(1.0f, 0.0f);
        glVertex2f(173.0f, 0.0f);

    glEnd();
    glDisable(GL_BLEND);
    glDisable(GL_TEXTURE_2D);
}

抱歉没有说明。它是一个SDL_Color g_textColor = {255, 0, 0, 0}; (我尝试过指定alpha值和不指定,但得到的结果相同)。 - ForceMagic
如果您没有使用SDL blitting机制,为什么要使用SDL_DisplayFormatAlpha()呢? - genpfault
@genpfault 这是我的一个问题之一。我不确定如何将整个SDL_Blit与TTF_RenderUTF8_Blended一起使用,我尝试了从所读的不同方法。然而,显然我没有正确地使用某些东西,这就是为什么我需要帮助的原因。我需要有人能够指出我做错了什么。 - ForceMagic
1个回答

4
你犯了一个比较常见的错误。这个问题出现在OpenGL方面。
当你在DrawText()中渲染纹理时,你启用了OpenGL的混合能力,但是你没有指定混合函数(即应该如何混合)!
你需要使用以下代码来启用OpenGL中的普通alpha混合:
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

这些信息曾经在OpenGL网站上,但现在我找不到了。

这应该可以阻止它变成纯红色。其他的原因是因为它们没有alpha混合,它们实际上只是带有没有alpha通道的红色-黑色图像,所以混合函数并不重要。但混合的那个只包含红色,带有一个alpha通道使其更少红。

我注意到你的程序还有一些小问题。

DrawText()函数中,你正在使用SDL blitting来绘制表面,并使用OpenGL进行渲染。当使用OpenGL时,不应该使用常规的SDL blitting;它不起作用。所以这行代码不应该存在:

SDL_BlitSurface(g_pText, &sourceRect, g_pSurfaceDisplay, NULL);

此外,这行代码会泄露内存:

g_pText = SDL_DisplayFormatAlpha( TTF_RenderUTF8_Blended(...) );
TTF_RenderUTF8_Blended()返回一个指向SDL_Surface的指针,需要使用SDL_FreeSurface()进行释放。由于您将其传递给SDL_DisplayFormatAlpha(),因此您失去了对它的跟踪,它永远不会被释放(因此存在内存泄漏)。
好消息是,您在这里不需要SDL_DisplayFormatAlpha,因为TTF_RenderUTF8_Blended返回一个具有alpha通道的32位表面!因此,您可以重写此行为:
g_pText = TTF_RenderUTF8_Blended(g_pFont, "My first Text!", g_textColor);

太棒了,我刚刚测试了一下,它完美地运行了。谢谢你的解释,有时候当你只是试图解决问题时,事情会堆积在一起,很难找到答案。 - ForceMagic
1
没问题,这是一个容易犯的错误。glBlendFunc有点复杂,但你在这里看到的用法99%的时间都是这样的。就像我说的,这些信息曾经在OpenGL的常见问题解答中,但现在已经消失了。 - Daniel Hanrahan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接