尝试渲染 SDL_Texture 时 C++ SDL2 错误:无效纹理

2024-05-16

我正在尝试制作一个简单的游戏,当我尝试渲染我的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();
}

我四处搜寻,找不到任何可以解释我的错误的内容。我能找到的最接近的东西是这个问题 https://stackoverflow.com/questions/25569985/sdl-invalid-texture-error-on-sdl-destroytexture,但该错误是由于渲染器在纹理之前被破坏而引起的,这不是我的情况。

我真的希望有人能告诉我可能导致此错误的原因,任何建议都会受到赞赏!


你的问题是你正在这一行复制你的纹理

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

由于您没有定义复制赋值运算符或移动赋值,因此编译器为您提供了一个,它只是按原样复制成员。

一旦临时创建Texture(renderer, "gfx/grid.bmp");被摧毁,graphic_grid.texture不再有效。您可以通过摆脱您的Texture析构函数,你应该发现一切都按预期工作(当然你不actually想要这样做,这不是解决办法)。

您将需要实现移动赋值或复制赋值构造函数,如果您的情况最好是前者Textures 并不意味着被复制(并且由于您需要分配,您还应该提供一个移动/复制构造函数,以及按照五规则的其他两个移动/复制方法,或者至少明确地delete them).

请仔细阅读0/3/5的规则

C++11 中的“三法则”变成了“五法则”? https://stackoverflow.com/questions/4782757/rule-of-three-becomes-rule-of-five-with-c11

如果您使用的是 GCC-Weffc++flag 会警告您像这样的狡猾的类设计的某些部分。

就我个人而言,我尝试尽可能地将句柄和指针包装到 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)。

您的代码还有一些其他奇怪的事情,例如从构造函数过早返回。如果无法构造对象,则应该抛出异常。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

尝试渲染 SDL_Texture 时 C++ SDL2 错误:无效纹理 的相关文章

  • 属性对象什么时候创建?

    由于属性实际上只是附加到程序集的元数据 这是否意味着属性对象仅根据请求创建 例如当您调用 GetCustomAttributes 时 或者它们是在创建对象时创建的 或者 前两个的组合 在由于 CLR 的属性扫描而创建对象时创建 从 CLR
  • 模板类的不明确多重继承

    我有一个真实的情况 可以总结为以下示例 template lt typename ListenerType gt struct Notifier void add listener ListenerType struct TimeListe
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • 使用向量的 merge_sort 在少于 9 个输入的情况下效果很好

    不知何故 我使用向量实现了合并排序 问题是 它可以在少于 9 个输入的情况下正常工作 但在有 9 个或更多输入的情况下 它会执行一些我不明白的操作 如下所示 Input 5 4 3 2 1 6 5 4 3 2 1 9 8 7 6 5 4 3
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • Bing 地图运行时错误 Windows 8.1

    当我运行带有 Bing Map 集成的 Windows 8 1 应用程序时 出现以下错误 Windows UI Xaml Markup XamlParseException 类型的异常 发生在 DistanceApp exe 中 但未在用户
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的
  • 如何将字符串“07:35”(HH:MM) 转换为 TimeSpan

    我想知道是否有办法将 24 小时时间格式的字符串转换为 TimeSpan 现在我有一种 旧时尚风格 string stringTime 07 35 string values stringTime Split TimeSpan ts new
  • 为什么 strtok 会导致分段错误?

    为什么下面的代码给出了Seg 最后一行有问题吗 char m ReadName printf nRead String s n m Writes OK char token token strtok m 如前所述 读取字符串打印没有问题 但
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐