gpt4 book ai didi

c++ - 使用 SDL2 渲染文本,更新纹理/输出时出现问题

转载 作者:行者123 更新时间:2023-12-02 10:22:33 25 4
gpt4 key购买 nike

我最近开始在一个C++项目中使用SDL2,主要是作为一个培训项目,所以我可以学习使用SDL2。
我尝试过的一件事是编写一个简单的标签类。想法是在开始时使用给定的位置和尺寸创建标签。然后,当我调用我的“setText()”函数时,文本将被渲染并显示在窗口上。起初我使用这种方法:

// get a surface from given text    
m_surf = TTF_RenderText_Solid(m_font, txt.c_str(), fgCol);
// get a texture from the previous surface
m_texture = SDL_CreateTextureFromSurface(r, m_surf);
// render it in 'r' which is the window renderer
SDL_RenderCopy(r, m_texture, NULL, &rect);

这对我有用。所以我想消除每次文本更改时创建纹理的开销,然后销毁它们,并使用 SDL_UpdateTexture() .
好吧,这从来没有奏效!即使调用成功,它也总是在屏幕上产生损坏的输出:
// Once at ctor create a texture
m_texture = SDL_CreateTexture(r, SDL_PIXELFORMAT_RGBA32,SDL_TEXTUREACCESS_STATIC, rect.w, rect.h);
// ...
// later update when setText() is called get a surface from given text and update texture
m_surf = TTF_RenderText_Solid(m_font, txt.c_str(), fgCol);
rc = SDL_UpdateTexture(m_texture, NULL, m_surf->pixels, m_surf->pitch);

我的第一个想法是像素格式有问题......所以我在更新之前也使用了格式转换: m_surf = SDL_ConvertSurfaceFormat(ts, SDL_PIXELFORMAT_RGBA32, 0);其中“ts”是渲染文本的临时表面,常量 SDL_PIXELFORMAT_RGBA32 与我用来创建 m_texture 的相同。

这是我在使用“SDL_UpdateTexture()”时在窗口上看到的内容
corrupt output

有任何想法吗 ?

谢谢,
亚历克斯

代码片段:
我写了一段与重现问题相关的紧凑代码
// label class declaration
class label
{
friend class panel;
public:
label(SDL_Window* const w, TTF_Font* const fnt, SDL_Rect rect);
~label();

int draw(SDL_Rect& rect);
int draw(SDL_Rect& rect,const std::string& txt, SDL_Color fgCol, int quality);

private:
std::string m_txt;
TTF_Font* const m_font = nullptr;
SDL_Surface *m_surf = nullptr;
SDL_Texture *m_texture = nullptr;
SDL_Rect m_rect{0,0,0,0};
SDL_Renderer *m_ren;
SDL_Window *m_wnd;
Uint32 m_pixForm;
};

// label class constructor
label::label(SDL_Window* const w, TTF_Font* const fnt, SDL_Rect rect):m_wnd(w),m_font(fnt),m_surf (nullptr), m_rect(rect)
{
// save window info locally for label object
m_ren =SDL_GetRenderer(m_wnd);
m_pixForm =SDL_GetWindowPixelFormat(m_wnd);
m_texture = SDL_CreateTexture(m_ren, m_pixForm,SDL_TEXTUREACCESS_STATIC, rect.w, rect.h);
m_surf = nullptr;
std::cout << "PixelFormat " << m_pixForm << " : " << SDL_GetPixelFormatName(m_pixForm) << std::endl;
}

// label class methods to render/draw text on screen
int label::setText(const std::string& txt, SDL_Color fgCol, int quality=0)
{
int w,h;
SDL_Surface *ts;
if(m_surf!=nullptr)SDL_FreeSurface(m_surf);
switch(quality)
{
case 1:
{
ts = TTF_RenderText_Shaded(m_font, txt.c_str(), fgCol, SDL_Color{0,0,0,0});
break;
}
case 2:
{
ts = TTF_RenderText_Blended(m_font,txt.c_str(), fgCol);
break;
}
default:
{
ts = TTF_RenderText_Solid(m_font, txt.c_str(), fgCol);
break;
}
}
std::cout << "Before pixFormat ts " << SDL_GetPixelFormatName(ts->format->format)<< std::endl;
m_surf = SDL_ConvertSurfaceFormat(ts, m_pixForm, 0);
std::cout << "After pixFormat surf : " << SDL_GetPixelFormatName(m_surf->format->format) << " ts " << SDL_GetPixelFormatName(ts->format->format)<< std::endl;
SDL_FreeSurface(ts);
TTF_SizeText(m_font, txt.c_str(), &w, &h);
std::cout << "Set text '" << txt << "' w: " << w << " h: " << h << std::endl;
}

int label::draw(SDL_Rect& rect)
{
// HERE is the one that draw the noise on screen!
{
int rc;
rc = SDL_UpdateTexture(m_texture, NULL, m_surf->pixels, m_surf->pitch);
if(rc)
{
std::cout << "Error updating texture " << rc <<std::endl;
return(rc);
}
}
// if it is replaced with the following it works:
/*
{
if(m_texture!=nullptr)SDL_DestroyTexture(m_texture);
m_texture = SDL_CreateTextureFromSurface(r, m_surf);
}
*/

SDL_RenderCopy(m_ren, m_texture, NULL, &rect);
}

int label::draw(SDL_Rect& rect,const std::string& txt, SDL_Color fgCol, int q)
{
setText(txt,fgCol,q);
draw(rect);
}

// main functiom. Init SDL, create window, create label and draw it:
int main( int argc, char * argv[] )
{
SDL_Window *wnd ;
SDL_Renderer *wrend;
int i;

wnd = SDL_CreateWindow("TestWin",SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,500,300,0);
wrend = SDL_CreateRenderer(wnd,-1,SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawBlendMode(wrend,SDL_BLENDMODE_ADD);
SDL_SetRenderDrawColor(wrend,0,0,0,255);
SDL_RenderClear(wrend);

SDL_Color fcol{255,255,0,128};
SDL_Rect lblBox;
lblBox.h = 120;
lblBox.w = 280;
lblBox.x = 1;
lblBox.y = 1;

label lbl(wnd, getCurrentFont(), lblBox); // create a label (getCurrentFont returns a valid TTF_Font pointer)
lbl.draw(lblBox,std::string("Text Test"), fcol, 2);
SDL_RenderPresent(wrend);
SDL_ShowWindow(wnd);
// .. more code here
}

最佳答案

我在 MacOS Catalina 和最新版本的 SDL2 和 SDL2_ttf 上测试了您的代码,并且出现了段错误。

调试后发现在label::setText()你使用一个质量参数,如果你通过 quality=2 (使用函数 TTF_RenderText_Blended() ),你最终会出现段错误或垃圾像素。

但功能 TTF_RenderText_Shaded()TTF_RenderText_Solid()工作得很好,我认为这与 TTF_RenderText_Blended( 的事实直接相关。 ) 你有 透明度 在你的表面。

编辑:
在深入挖掘之后,我通过替换 NULL 中的 rect 值解决了我之前遇到的段错误:

 rc = SDL_UpdateTexture(m_texture,  NULL, m_surf->pixels, m_surf->pitch);

按 m_surf 的大小:
SDL_Rect SurfRect;

SurfRect.x = 0;
SurfRect.y = 0;
SurfRect.w = m_surf->w;
SurfRect.h = m_surf->h;
...
rc = SDL_UpdateTexture(m_texture, SurfRect, m_surf->pixels, m_surf->pitch);

编辑 2:
我直接查看了 SDL2 的源文件,以了解我的测试与函数 SDL_CreateTexture() 内部完成的代码之间的区别。你必须添加这些行:
int rc = SDL_UpdateTexture(m_texture, &SurfRect, m_surf->pixels, m_surf->pitch);
{
Uint8 r, g, b, a;
SDL_BlendMode blendMode;
SDL_GetSurfaceColorMod(m_surf, &r, &g, &b);
SDL_SetTextureColorMod(m_texture, r, g, b);

SDL_GetSurfaceAlphaMod(m_surf, &a);
SDL_SetTextureAlphaMod(m_texture, a);

if (SDL_HasColorKey(m_surf)) {
/* We converted to a texture with alpha format */
SDL_SetTextureBlendMode(m_texture, SDL_BLENDMODE_BLEND);
} else {
SDL_GetSurfaceBlendMode(m_surf, &blendMode);
SDL_SetTextureBlendMode(m_texture, blendMode);
}
}

Result for TTF_RenderText_Blended()
查找 here我的原始调试文件(这不漂亮)

关于c++ - 使用 SDL2 渲染文本,更新纹理/输出时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59485384/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com