SDL2加载某些纹理使SDL_RenderFillRect颜色怪异
SDL2 load certain texture make SDL_RenderFillRect color weird
我做了一个程序,有两种不同的状态,一种是菜单显示-"Menu State",另一种是画东西-"Draw State".
但是我遇到了一件奇怪的事情,如果我加载某些 png 作为纹理并将它们复制到渲染器以显示,然后离开 "Menu State" 进入 "Draw State"。纹理会以某种方式使矩形颜色无法正确显示(例如使绿色变暗)。
在我的代码中,切换到新状态(调用 MenuState::onExit())将擦除纹理图(使用 std::string 索引的纹理智能指针图)
所以加载的纹理甚至不存在于 "Drawing State".
我不知道出了什么问题。这是我的一些代码
void TextureManager::DrawPixel(int x, int y, int width, int height, SDL_Renderer *pRenderer)
{
SDL_Rect rect;
rect.x = x;
rect.y = y;
rect.w = width;
rect.h = height;
SDL_SetRenderDrawColor(pRenderer, 0, 255, 0, 255);//same color value
SDL_RenderFillRect(pRenderer, &rect);
}
static bool TextureManagerLoadFile(std::string filename, std::string id)
{
return TextureManager::Instance().Load(filename, id, Game::Instance().GetRenderer());
}
bool TextureManager::Load(std::string filename, std::string id, SDL_Renderer *pRenderer)
{
if(m_textureMap.count(id) != 0)
{
return false;
}
SDL_Surface *pTempSurface = IMG_Load(filename.c_str());
SDL_Texture *pTexutre = SDL_CreateTextureFromSurface(pRenderer, pTempSurface);
SDL_FreeSurface(pTempSurface);
if(pTexutre != 0)
{
m_textureMap[id] = std::make_unique<textureData>(pTexutre, 0, 0);
SDL_QueryTexture(pTexutre, NULL, NULL, &m_textureMap[id]->width, &m_textureMap[id]->height);
return true;
}
return false;
}
void TextureManager::ClearFromTextureMap(std::string textureID)
{
m_textureMap.erase(textureID);
}
bool MenuState::onEnter()
{
if(!TextureManagerLoadFile("assets/Main menu/BTN PLAY.png", "play_button"))
{
return false;
}
if(!TextureManagerLoadFile("assets/Main menu/BTN Exit.png", "exit_button"))
//replace different png file here will also affect the outcome
{
return false;
}
if(!TextureManagerLoadFile("assets/Main menu/BTN SETTINGS.png", "setting_button"))
{
return false;
}
int client_w,client_h;
SDL_GetWindowSize(Game::Instance().GetClientWindow(),&client_w, &client_h);
int playBtn_w = TextureManager::Instance().GetTextureWidth("play_button");
int playBtn_h = TextureManager::Instance().GetTuextureHeight("play_button");
int center_x = (client_w - playBtn_w) / 2;
int center_y = (client_h - playBtn_h) / 2;
ParamsLoader pPlayParams(center_x, center_y, playBtn_w, playBtn_h, "play_button");
int settingBtn_w = TextureManager::Instance().GetTextureWidth("setting_button");
int settingBtn_h = TextureManager::Instance().GetTuextureHeight("setting_button");
ParamsLoader pSettingParams(center_x , center_y + (playBtn_h + settingBtn_h) / 2, settingBtn_w, settingBtn_h, "setting_button");
int exitBtn_w = TextureManager::Instance().GetTextureWidth("exit_button");
int exitBtn_h = TextureManager::Instance().GetTuextureHeight("exit_button");
ParamsLoader pExitParams(10, 10, exitBtn_w, exitBtn_h, "exit_button");
m_gameObjects.push_back(std::make_shared<MenuUIObject>(&pPlayParams, s_menuToPlay));
m_gameObjects.push_back(std::make_shared<MenuUIObject>(&pSettingParams, s_menuToPlay));
m_gameObjects.push_back(std::make_shared<MenuUIObject>(&pExitParams, s_menuExit));
//change order of the 3 line code above
//or replace different png for exit button, will make the rectangle color different
std::cout << "Entering Menu State" << std::endl;
return true;
}
bool MenuState::onExit()
{
for(auto i : m_gameObjects)
{
i->Clean();
}
m_gameObjects.clear();
TextureManager::Instance().ClearFromTextureMap("play_button");
TextureManager::Instance().ClearFromTextureMap("exit_button");
TextureManager::Instance().ClearFromTextureMap("setting_button");
std::cout << "Exiting Menu State" << std::endl;
return true;
}
void Game::Render()
{
SDL_SetRenderDrawColor(m_pRenderer, 255, 255, 255, 255);
SDL_RenderClear(m_pRenderer);
m_pGameStateMachine->Render();
SDL_RenderPresent(m_pRenderer);
}
Menu State Figure
Correct Color
Wrong Color
edit :此外,我发现这种奇怪的现象仅在使用 'SDL_RENDERER_ACCELERATED' 标志和 -1 或 0 驱动程序索引创建渲染器时发生,即 SDL_CreateRenderer(m_pWindow, 1, SDL_RENDERER_ACCELERATED);
或 SDL_CreateRenderer(m_pWindow, -1, SDL_RENDERER_SOFTWARE);
工作正常!
我遇到了同样的问题。尝试渲染浅灰色时,我得到了鲜艳的绿色。
为您解决问题的参数组合与要使用的驱动程序有关。 -1
选择第一个满足条件的驱动程序,在这种情况下需要加速。
使用 SDL_GetRendererInfo
我能够在使用 "direct3d" 驱动程序时看到这种情况。
我发现 this question 谈论在 direct3d 中混合。
I figured it out eventually. In addition to Alpha Blending there is a Color Blending. So DirectX merges color of the last texture with the last primitive.
该问题确实在 DirectX 中提供了对此的修复,但我不确定如何将其应用于 SDL。我也未能在 SDL 中找到解决此问题的方法。
我正在用 SDL_ttf 绘制绿色文本,它使用了纹理。然后在屏幕上的其他地方为另一个组件绘制一个灰色矩形。
奇怪的是它似乎并不是一直都在发生。然而,我的似乎主要发生在 SDL_ttf 上。起初我认为它可能是 TTF_RenderText_Blended
的副产品,但是,它也发生在其他人身上。它似乎也不受那些函数生成的纹理混合模式的影响
所以在我的例子中,我能够更改操作顺序以获得正确的颜色。
或者,使用 OpenGL 驱动程序似乎也可以解决此问题。 与您提到的类似。 (这对我来说是驱动程序索引 1)
我不确定这是否归类为 "Answer",但希望它能帮助某人或为他们指明正确的方向。
我一直被这个问题困扰。 ekodes 提供的 link 是我解决它的方法,因为操作顺序对我没有影响。
我能够通过 SDL_RenderGetD3D9Device(), then SetTextureStageState as described in ekodes d3d blending link 提取 d3d9Device。
我做了一个程序,有两种不同的状态,一种是菜单显示-"Menu State",另一种是画东西-"Draw State".
但是我遇到了一件奇怪的事情,如果我加载某些 png 作为纹理并将它们复制到渲染器以显示,然后离开 "Menu State" 进入 "Draw State"。纹理会以某种方式使矩形颜色无法正确显示(例如使绿色变暗)。
在我的代码中,切换到新状态(调用 MenuState::onExit())将擦除纹理图(使用 std::string 索引的纹理智能指针图)
所以加载的纹理甚至不存在于 "Drawing State".
我不知道出了什么问题。这是我的一些代码
void TextureManager::DrawPixel(int x, int y, int width, int height, SDL_Renderer *pRenderer)
{
SDL_Rect rect;
rect.x = x;
rect.y = y;
rect.w = width;
rect.h = height;
SDL_SetRenderDrawColor(pRenderer, 0, 255, 0, 255);//same color value
SDL_RenderFillRect(pRenderer, &rect);
}
static bool TextureManagerLoadFile(std::string filename, std::string id)
{
return TextureManager::Instance().Load(filename, id, Game::Instance().GetRenderer());
}
bool TextureManager::Load(std::string filename, std::string id, SDL_Renderer *pRenderer)
{
if(m_textureMap.count(id) != 0)
{
return false;
}
SDL_Surface *pTempSurface = IMG_Load(filename.c_str());
SDL_Texture *pTexutre = SDL_CreateTextureFromSurface(pRenderer, pTempSurface);
SDL_FreeSurface(pTempSurface);
if(pTexutre != 0)
{
m_textureMap[id] = std::make_unique<textureData>(pTexutre, 0, 0);
SDL_QueryTexture(pTexutre, NULL, NULL, &m_textureMap[id]->width, &m_textureMap[id]->height);
return true;
}
return false;
}
void TextureManager::ClearFromTextureMap(std::string textureID)
{
m_textureMap.erase(textureID);
}
bool MenuState::onEnter()
{
if(!TextureManagerLoadFile("assets/Main menu/BTN PLAY.png", "play_button"))
{
return false;
}
if(!TextureManagerLoadFile("assets/Main menu/BTN Exit.png", "exit_button"))
//replace different png file here will also affect the outcome
{
return false;
}
if(!TextureManagerLoadFile("assets/Main menu/BTN SETTINGS.png", "setting_button"))
{
return false;
}
int client_w,client_h;
SDL_GetWindowSize(Game::Instance().GetClientWindow(),&client_w, &client_h);
int playBtn_w = TextureManager::Instance().GetTextureWidth("play_button");
int playBtn_h = TextureManager::Instance().GetTuextureHeight("play_button");
int center_x = (client_w - playBtn_w) / 2;
int center_y = (client_h - playBtn_h) / 2;
ParamsLoader pPlayParams(center_x, center_y, playBtn_w, playBtn_h, "play_button");
int settingBtn_w = TextureManager::Instance().GetTextureWidth("setting_button");
int settingBtn_h = TextureManager::Instance().GetTuextureHeight("setting_button");
ParamsLoader pSettingParams(center_x , center_y + (playBtn_h + settingBtn_h) / 2, settingBtn_w, settingBtn_h, "setting_button");
int exitBtn_w = TextureManager::Instance().GetTextureWidth("exit_button");
int exitBtn_h = TextureManager::Instance().GetTuextureHeight("exit_button");
ParamsLoader pExitParams(10, 10, exitBtn_w, exitBtn_h, "exit_button");
m_gameObjects.push_back(std::make_shared<MenuUIObject>(&pPlayParams, s_menuToPlay));
m_gameObjects.push_back(std::make_shared<MenuUIObject>(&pSettingParams, s_menuToPlay));
m_gameObjects.push_back(std::make_shared<MenuUIObject>(&pExitParams, s_menuExit));
//change order of the 3 line code above
//or replace different png for exit button, will make the rectangle color different
std::cout << "Entering Menu State" << std::endl;
return true;
}
bool MenuState::onExit()
{
for(auto i : m_gameObjects)
{
i->Clean();
}
m_gameObjects.clear();
TextureManager::Instance().ClearFromTextureMap("play_button");
TextureManager::Instance().ClearFromTextureMap("exit_button");
TextureManager::Instance().ClearFromTextureMap("setting_button");
std::cout << "Exiting Menu State" << std::endl;
return true;
}
void Game::Render()
{
SDL_SetRenderDrawColor(m_pRenderer, 255, 255, 255, 255);
SDL_RenderClear(m_pRenderer);
m_pGameStateMachine->Render();
SDL_RenderPresent(m_pRenderer);
}
Menu State Figure
Correct Color
Wrong Color
edit :此外,我发现这种奇怪的现象仅在使用 'SDL_RENDERER_ACCELERATED' 标志和 -1 或 0 驱动程序索引创建渲染器时发生,即 SDL_CreateRenderer(m_pWindow, 1, SDL_RENDERER_ACCELERATED);
或 SDL_CreateRenderer(m_pWindow, -1, SDL_RENDERER_SOFTWARE);
工作正常!
我遇到了同样的问题。尝试渲染浅灰色时,我得到了鲜艳的绿色。
为您解决问题的参数组合与要使用的驱动程序有关。 -1
选择第一个满足条件的驱动程序,在这种情况下需要加速。
使用 SDL_GetRendererInfo
我能够在使用 "direct3d" 驱动程序时看到这种情况。
我发现 this question 谈论在 direct3d 中混合。
I figured it out eventually. In addition to Alpha Blending there is a Color Blending. So DirectX merges color of the last texture with the last primitive.
该问题确实在 DirectX 中提供了对此的修复,但我不确定如何将其应用于 SDL。我也未能在 SDL 中找到解决此问题的方法。
我正在用 SDL_ttf 绘制绿色文本,它使用了纹理。然后在屏幕上的其他地方为另一个组件绘制一个灰色矩形。
奇怪的是它似乎并不是一直都在发生。然而,我的似乎主要发生在 SDL_ttf 上。起初我认为它可能是 TTF_RenderText_Blended
的副产品,但是,它也发生在其他人身上。它似乎也不受那些函数生成的纹理混合模式的影响
所以在我的例子中,我能够更改操作顺序以获得正确的颜色。
或者,使用 OpenGL 驱动程序似乎也可以解决此问题。 与您提到的类似。 (这对我来说是驱动程序索引 1)
我不确定这是否归类为 "Answer",但希望它能帮助某人或为他们指明正确的方向。
我一直被这个问题困扰。 ekodes 提供的 link 是我解决它的方法,因为操作顺序对我没有影响。
我能够通过 SDL_RenderGetD3D9Device(), then SetTextureStageState as described in ekodes d3d blending link 提取 d3d9Device。