【问题标题】:SDL2 load certain texture make SDL_RenderFillRect color weirdSDL2 加载某些纹理使 SDL_RenderFillRect 颜色奇怪
【发布时间】:2020-01-17 03:11:55
【问题描述】:

我做了一个程序,它有两种不同的状态,一种用于菜单显示——“Menu State”,另一种状态用于绘制一些东西——“Draw State”。
但是我遇到了一个奇怪的事情,如果我为纹理加载某些 png 并将它们复制到渲染器以显示,然后离开“菜单状态”进入“绘制状态”。纹理会以某种方式使矩形颜色无法正确显示(例如使绿色变暗)。
在我的代码中,切换到新状态(调用 MenuState::onExit())将擦除纹理映射(使用 std::string 索引的纹理智能指针映射)
所以加载的纹理甚至不存在于“绘图状态”中。
我不知道出了什么问题。这是我的一些代码

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);works很好!

【问题讨论】:

    标签: c++ sdl-2


    【解决方案1】:

    我一直被同样的问题所困扰。 ekodes 提供的链接是我解决它的方法,因为操作顺序对我没有影响。

    我能够通过SDL_RenderGetD3D9Device() 拉出d3d9Device,然后是SetTextureStageState,如ekodes d3d blending link 中所述。

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题。尝试渲染浅灰色时,我得到了鲜艳的绿色。

      为您解决问题的参数组合与要使用的驱动程序有关。 -1 选择第一个满足条件的驱动程序,在这种情况下需要加速。

      使用SDL_GetRendererInfo 我可以看到在使用“direct3d”驱动程序时会发生这种情况。

      我发现this question 谈论在direct3d 中进行混合。

      我终于明白了。除了 Alpha Blending,还有一个 Color Blending。所以 DirectX 将最后一个纹理的颜色与最后一个图元合并。

      这个问题确实在 DirectX 中提供了一个解决方案,但是我不确定如何将它应用于 SDL。我也无法在 SDL 中找到解决此问题的方法。

      我正在使用 SDL_ttf 绘制绿色文本,它使用纹理。然后为屏幕上其他地方的另一个组件绘制一个灰色矩形。

      奇怪的是它似乎并不总是发生。然而,我的似乎主要发生在 SDL_ttf 上。起初我认为这可能是TTF_RenderText_Blended 的副产品,但它也发生在其他产品中。它似乎也不受这些函数生成的纹理混合模式的影响

      所以在我的例子中,我能够更改操作的顺序以获得正确的颜色。

      或者,使用 OpenGL 驱动程序似乎也可以解决此问题。 与您提到的类似。 (这对我来说是驱动索引 1)

      我不确定这是否属于“答案”,但希望它可以帮助某人或为他们指明正确的方向。

      【讨论】:

      • 是的,看起来我们遇到了同样的问题。更改操作顺序也对我有用,尽管确定正确的顺序很麻烦。我想知道这个问题是否与硬件方面的 SDL 兼容性有关。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-12
      • 2012-02-22
      • 1970-01-01
      • 2014-11-04
      • 1970-01-01
      相关资源
      最近更新 更多