簡體   English   中英

嘗試渲染 SDL_Texture 時出現 C++ SDL2 錯誤:紋理無效

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

我正在嘗試制作一個簡單的游戲,當我嘗試渲染我的SDL_Texture ,出現了一個莫名其妙的錯誤。 我已經正確設置了一切,我能夠使用SDL_RenderClear成功清除屏幕,並且我的紋理不為空,因此它應該已正確創建。 但是當我嘗試調用render()函數時出現錯誤,並且SDL_GetError()返回“無效紋理”。

編輯:我現在已經按照要求創建了一個 MCVE,我對其進行了測試以驗證它是否重現了錯誤。 它應該在窗口中的路徑“gfx/grid.bmp”處顯示圖像,但它給了我錯誤。 這是完整的 MCVE:

#include <SDL.h>
#include <string>
#include <iostream>
#undef main

class Texture{
private:
    SDL_Texture* texture;
    SDL_Renderer* renderer;
    int width;
    int height;
public:
    Texture(){
        texture = nullptr;
    }
    Texture (SDL_Renderer* ren, std::string path){
        texture = nullptr;
        SDL_Surface* surface = nullptr;
        surface = SDL_LoadBMP(path.c_str());
        if(surface == nullptr) return;
        renderer = ren;

        texture = SDL_CreateTextureFromSurface( renderer, surface );
        if(texture == 0) return;

        width = surface->w;
        height = surface->h;

        SDL_FreeSurface(surface);
        std::cout << "Texture '" << path << "' successfully loaded\n";
    }
    bool loaded(){
        return texture != 0;
    }
    bool render(int x = 0, int y = 0){
        SDL_Rect dest;
        dest.x = x;
        dest.y = y;
        dest.w = width;
        dest.h = height;
        return SDL_RenderCopy(renderer, texture, nullptr, &dest) == 0;
    }
    void unload(){
        if(loaded()){
            SDL_DestroyTexture(texture);
            texture = nullptr;
            renderer = nullptr;
            width = 0;
            height = 0;
        }
    }
    ~Texture(){
        unload();
    }
};

class CApp{
private:
    bool running = true;

    SDL_Window* window = nullptr;
    SDL_Renderer* renderer = nullptr;
    Texture graphic_grid;
    bool render = true;
public:
    int OnExecute();

    bool OnInit();
    void OnEvent(SDL_Event* event);
    void OnRender();
    void OnCleanup();
};

bool CApp::OnInit(){
    if(SDL_Init(SDL_INIT_EVERYTHING) < 0){
        return false;
    }
    if((window = SDL_CreateWindow("Simple Tic-Tac-Toe", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 600, 600, SDL_WINDOW_SHOWN)) == nullptr){
        return false;
    }
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if(renderer == nullptr){
        std::cout << "Renderer failed to load! Error: " << SDL_GetError();
        return false;
    }
    SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF );

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

    if(!graphic_grid.loaded()){
        std::cout << "Image failed to load! Error: " << SDL_GetError();
        return false;
    }

    std::cout << "Initialized fully\n";

    return true;
}

void CApp::OnEvent(SDL_Event* event){
    switch(event->type == SDL_QUIT){
        running = false;
    }
}

void CApp::OnRender(){
    if(!render) return;

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

    if(!graphic_grid.loaded()){
        std::cout << "Texture not loaded!\n";
    }else{
        std::cout << "Texture not null!\n";
    }

    //This is the place where I get the "Invalid texture" error, everything else works fine
    if(!graphic_grid.render()){
        std::cout << "Failed to render image! Error: " << SDL_GetError() << '\n';
    }

    SDL_RenderPresent(renderer);

    render = false;
}

void CApp::OnCleanup(){
    graphic_grid.unload();

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    renderer = nullptr;
    window = nullptr;

    SDL_Quit();
}

int CApp::OnExecute(){
    if(OnInit() == false){
        return -1;
    }

    SDL_Event event;
    while(running){

        while(SDL_PollEvent(&event)){
            OnEvent(&event);
        }

        OnRender();
    }

    OnCleanup();

    return 0;
}

int main(){
    CApp theApp;
    return theApp.OnExecute();
}

我四處搜索,找不到任何可以解釋我的錯誤可能是什么的東西。 我能找到的最接近的是這個問題,但該錯誤是由渲染器在紋理之前被破壞引起的,這不是我的情況。

我真的希望有人能告訴我可能導致此錯誤的原因,任何建議表示贊賞!

你的問題是你在這一行復制你的紋理

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

由於您沒有定義復制賦值運算符或移動賦值,編譯器為您提供了一個,它只是按原樣復制成員。

一旦由Texture(renderer, "gfx/grid.bmp");創建的臨時文件Texture(renderer, "gfx/grid.bmp"); 被銷毀, graphic_grid.texture不再有效。 您可以通過擺脫TextureTexture函數來測試這一點,您應該會發現一切都按預期工作(當然您實際上並不想這樣做,這不是解決方法)。

您將需要實現移動分配或復制分配構造函數,如果您的Texture不打算被復制,最好是前者(並且由於您需要分配,您還應該提供一個移動/復制構造函數,以及其他兩個根據五項規則移動/復制方法,或至少明確delete它們)。

請仔細閱讀 0/3/5 規則

在 C++11 中三分法變成五分法?

如果你正在使用 GCC, -Weffc++標志會警告你關於像這樣狡猾的類設計的某些部分。

就我個人而言,我嘗試盡可能將句柄和指針包裝到 RAII 類型中,只要每個成員對自己負責,您通常就不必對復制和移動構造函數胡說八道。 std::unique_ptr對此非常有效,例如:

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

可以如下使用

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

如果你像上面那樣包裝SDL_Texture那么你的Texture類將有一個隱式的移動構造函數和移動賦值運算符,它們可以開箱即用(但是,你必須擺脫renderer成員,或者以不同的方式處理它,例如使其成為std::shared_ptr以便它不會與紋理一起銷毀,除非其引用計數為 0)。

您的代碼還有一些其他奇怪的事情,例如過早從構造函數返回。 如果無法構造對象,則應拋出異常。

我不知道您調用哪個構造函數來創建 Texture 類的對象,我認為您創建的表面存在一些問題。 我已經嘗試了您的代碼並進行了一些更改,並且運行良好,

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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM