2017-07-21 7 views
1

SDLのかなり大きなアプリでしばらく働いていて、最近奇妙なバグに気付きました。ウィンドウが閉じられるたびに、別のウィンドウのすべてが完全に黒くレンダリングされます。赤を線で描くと黒くなり、SDL_Textureを描くと画像の代わりに黒い四角形が描かれます。SDL_Textureはすべてを黒にレンダリングさせます

しばらくすると、単純化したバージョンのアプリを初めから作り直すことで問題を再現することができました。このプログラムには、ウィンドウ、そのレンダラ、およびSDL_Textureを格納するウィンドウクラスが含まれています。ウィンドウクラスには、SDL_Textureを含むウィンドウを表示するレンダー機能も含まれています。各ウィンドウオブジェクトが閉じられているウィンドウなどのSDLイベントを処理できるようにする関数もあります。ウィンドウが閉じられると、ウィンドウ、レンダラー、およびテクスチャはすべて破棄されます。私は、より詳細に問題を説明し、私は私のコードを示していることを今

int main(int argc, const char * argv[]) { 

    if (SDL_Init(SDL_INIT_VIDEO) < 0) { // initialize SDL and IMG 
     printf("SDL could not initialize! Error: %s\n", SDL_GetError()); 
    } else if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) { 
     printf("SDL_image could not initialize! Error: %s\n", IMG_GetError()); 
    } else { 
     std::vector<Window*> windows; // vector of window objects 

     // add window objects to the vector 
     windows.push_back(new Window()); 
     windows.push_back(new Window()); 
     windows.push_back(new Window()); 
     windows.push_back(new Window()); 

     // initialize all windows 
     for (int i = 0; i < windows.size(); i++) { 
      windows[i]->init(); 
     } 

     // game loop 
     bool loop = true; 
     while (loop) { 
      SDL_Delay(50); // delay between each frame 

      // render all windows 
      for (int i = 0; i < windows.size(); i++) { 
       windows[i]->render(); 
      } 

      // handle new events 
      SDL_Event e; 
      while (SDL_PollEvent(&e)) { 

       // loop backward through windows 
       // in case one of them has to be 
       // removed from the vector 
       for (unsigned long i = windows.size(); i-- > 0;) { 
        if (windows[i]->isRunning()) { 
         windows[i]->events(e); 
        } else { 
         // delete a window if it has been closed 
         delete windows[i]; 
         windows.erase(windows.begin() + i); 
        } 
       } 
      } 

      if (windows.empty()) { // if all windows are closed, 
       loop = false;  // stop the loop 
      } 
     } 

    } 

    return 0; 
} 

class Window { 
    SDL_Window *window; 
    SDL_Renderer *renderer; 
    Uint32 windowID; 

    SDL_Texture *texture; 

    void cleanup() { 
     SDL_DestroyWindow(window); 
     SDL_DestroyRenderer(renderer); 
     SDL_DestroyTexture(texture); 
    } 

    bool running = true; 
public: 

    void init() { 

     window = SDL_CreateWindow("Window", 50, 50, 721, 558, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); 
     renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 
     windowID = SDL_GetWindowID(window); 
     SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); 

     // load texture 
     SDL_Surface* loadedSurface = IMG_Load("picture.png"); 
     texture = SDL_CreateTextureFromSurface(renderer, loadedSurface); 
     SDL_FreeSurface(loadedSurface); 

    } 

    bool isRunning() { 
     return running; 
    } 

    void render() { 
     // clear the screen with a green color 
     SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF); 
     SDL_RenderClear(renderer); 

     // create a rectangle for drawing things 
     SDL_Rect rect = {0, 0, 100, 100}; 

     // draw a red rectangle 
     SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF); 
     SDL_RenderFillRect(renderer, &rect); 

     // draw the texture/image on top of the rectangle 
     if (SDL_RenderCopy(renderer, texture, NULL, &rect) < 0) { 
      printf("Unable to render texture! Error: %s\n", SDL_GetError()); 
     } 



     SDL_RenderPresent(renderer); 
    } 

    void events(SDL_Event &e) { 
     if (e.window.windowID == windowID && e.window.event == SDL_WINDOWEVENT_CLOSE) { 
      running = false; 
      cleanup(); 
     } 
    } 
}; 

主な機能は、一度に複数のウィンドウを管理し、個別にそれらの一つ一つSDLのイベントフィード。プログラムが起動すると、4つのウィンドウオブジェクトが作成され、ウィンドウがそれぞれ画面に表示されます。各ウィンドウが適切にレンダリングされ、PNGイメージが赤い矩形の上にオーバーレイされます。 4番目のウィンドウ、または最後に初期化されるウィンドウは、他のウィンドウが閉じられた後にのみ、画像の色、黒色の線などのレンダリングを行います。別の色でレンダリングする唯一のものはSDL_RenderClearです。これは上記のコードで緑色の背景をレンダリングするために使用したもので、黒い画像と長方形のシェイプを表示します。

テクスチャ、レンダラー、およびウィンドウがこの問題が発生した後も有効であることを確認し、エラーが発生していないことをテストしました。

少なくとも、問題の原因となる可能性のある解決方法があるかどうかを確認したいと思います。

+0

私はそれをテストして問題を解決しました – Mashpoe

答えて

2

レンダラがまだ生きている間はウィンドウを破棄しないでください。 cleanup()の中でメソッドを逆の順序で実行してみてください。

void cleanup() 
{ 
    SDL_DestroyTexture(texture); 
    SDL_DestroyRenderer(renderer); 
    SDL_DestroyWindow(window); 
} 
関連する問題