C++ SDL2 Error when trying to render SDL_Texture: Invalid texture

家住魔仙堡 提交于 2019-12-06 07:35:01
user657267

Your problem is that you are copying your Texture in this line

graphic_grid = Texture(renderer, "gfx/grid.bmp");

Since you do not define a copy assignment operator or a move assignment, the compiler provides one for you, which simply copies the members as-is.

As soon as the temporary created by Texture(renderer, "gfx/grid.bmp"); is destroyed, graphic_grid.texture is no longer valid. You can test this by getting rid of your Texture destructor, you should find everything works as expected (of course you don't actually want to do this, it isn't a fix).

You will need to implement either a move assignment or copy assignment constructor, preferably the former if your Textures are not meant to be copied (and since you need the assignment you should also provide a move/copy constructor too, along with the other two move/copy methods as per the rule of five, or at least explicitly delete them).

Please read up on the rule of 0/3/5

Rule-of-Three becomes Rule-of-Five with C++11?

If you are using GCC the -Weffc++ flag will warn you about some parts of dodgy class design like this.

Personally I try to wrap handles and pointers into RAII types as much as possible, as long as each member is responsible for itself you usually don't have to faff around with copy and move constructors. std::unique_ptr works quite well for this, e.g.:

template<typename T, void(*destroy)(T*), typename Ptr = std::unique_ptr<T, decltype(destroy)>>
struct Handle : public Ptr
{
  Handle(T*&& p): Ptr{p, destroy}
  {
    if (!*this)
      throw std::runtime_error{SDL_GetError()};
  }
};

using Window_h  = Handle<SDL_Window, SDL_DestroyWindow>;
using Surface_h = Handle<SDL_Surface, SDL_FreeSurface>;
// And so on for other handles

Can be used as follows

Window_h window{SDL_CreateWindow(
  "Hello world", 
  SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
  800, 600,
 0 
)};

If you were to wrap SDL_Texture as above then your Texture class would have an implicit move constructor and move assignment operator that would just work out of the box (you would have to get rid of the renderer member however, or handle it differently, for instance make it a std::shared_ptr so it isn't destroyed along with the texture unless its reference count is 0).

There's a few other odd things about your code, such as prematurely returning from a constructor. If an object cannot be constructed you should throw an exception.

Hemant Gangwar

I don't know which constructor you are calling to create object of your Texture class, I think there is some issue with the surface you are creating. I have tried your code with some changes and it is working fine,

void CApp::OnRender(){

    SDL_Window* pWindow;
    SDL_Renderer* render;
    SDL_Surface* surface;

    SDL_Init(SDL_INIT_VIDEO);
    // Create wndow 
    pWindow = SDL_CreateWindow( 
        "Dummy", 
        100, 
        100, 
        640, 480, 
        SDL_WINDOW_SHOWN); 
    // Create renderer 
    render = SDL_CreateRenderer(pWindow, -1, 0); 
    // Create Surface
    surface = SDL_GetWindowSurface(pWindow);

    // Creating object of class texture
    Texture graphic_grid(render, surface);

    if(SDL_RenderClear(render) == 0){
        std::cout << "Successfully cleared screen\n";
    }

    if(!graphic_grid.loaded()){
        std::cout << "Texture not loaded!\n";
    }else{
        std::cout << "Texture not null!\n";
    }
    if(!graphic_grid.render()){
        std::cout << "Failed to render image! Error: " << SDL_GetError() << '\n';
    }
    for(int i = 0; i < 9; i++){
        if(grid[i] == 0) continue;
        int x = i%3*200;
        int y = i/3*200;
        if(grid[i] == 1){
            graphic_x.render(x, y);
        }else{
            graphic_o.render(x, y);
        }
    }

    SDL_RenderPresent(render);

    render = false;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!