繁体   English   中英

SDL 2.0-无效的渲染器错误

[英]SDL 2.0 - Invalid Renderer Error

我对尝试解决这个问题感到非常沮丧。 我一直在关注http://lazyfoo.net/tutorials/SDL/index.php 然后,我尝试开始使用SDL2制作游戏,但很快遇到此错误:我无法在屏幕上渲染任何内容。 屏幕弹出,我可以正确清除所有内容。 如果我调用SDL_GetError(),则输出为“无效的渲染器”。 我检查了代码以尝试找出可能导致此错误的位置,并在互联网上搜索无济于事。 可能导致问题的原因是我有一个具有render方法的类。 此render方法在其纹理上调用render方法。 那可能是我以某种方式搞砸的地方,但我不知道。

源代码:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <string>
#include <stdio.h>

const int WINDOW_WIDTH = 1280;
const int WINDOW_HEIGHT= 960;

SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;

enum MOVEMENT_STATES
{
    DOWN1,
    DOWN2,
    LEFT1,
    LEFT2,
    RIGHT1,
    RIGHT2,
    UP1,
    UP2,
    MOVEMENT_STATES_TOTAL
};

//Texture wrapper class
class LTexture
{
    public:

        //Initializes variables
        LTexture(std::string path);

        //Deallocates memory
        ~LTexture();

        #ifdef _SDL_TTF_H
        //Creates image from font string
        bool loadFromRenderedText( std::string textureText, SDL_Color textColor );
        #endif

        //Deallocates texture
        void free();

        //Set color modulation
        void setColor( Uint8 red, Uint8 green, Uint8 blue );

        //Set blending
        void setBlendMode( SDL_BlendMode blending );

        //Set alpha modulation
        void setAlpha( Uint8 alpha );

        //Renders texture at given point
        void render( int x, int y, SDL_Rect* clip = NULL, double angle = 0.0, SDL_Point* center = NULL, SDL_RendererFlip flip = SDL_FLIP_NONE );

        //Gets image dimensions
        int getWidth();
        int getHeight();

    private:

        //Loads image at specified path
        bool loadFromFile( std::string path );

        //The actual hardware texture
        SDL_Texture* mTexture;

        //Image dimensions
        int mWidth;
        int mHeight;
};

//Sprite classes
class Entity
{
    public:

        Entity(int hp);

        ~Entity();

        //void handleEntity(); Unimplemented

        void render(int x, int y);

        int health;
        int maxHealth;

        LTexture* mCurrentTexture;
};

Entity::Entity(int hp)
{
    mCurrentTexture = NULL;

    health = hp;
    maxHealth = hp;
}

Entity::~Entity()
{
    mCurrentTexture = NULL;
}

void Entity::render(int x, int y)
{
    //If current texture is non-null, render it
    if (mCurrentTexture != NULL)
    {
        (*mCurrentTexture).render(x, y);
    }
    else
    {
        printf("Texture is null!\n");
    }
}

LTexture::LTexture(std::string path)
{
    //Initialize
    mTexture = NULL;
    loadFromFile(path);
    mWidth = 0;
    mHeight = 0;
}

LTexture::~LTexture()
{
    //Deallocate
    free();
}

bool LTexture::loadFromFile( std::string path )
{
    //Get rid of preexisting texture
    free();

    //The final texture
    SDL_Texture* newTexture = NULL;

    //Load image at specified path
    SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
    if( loadedSurface == NULL )
    {
        printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
    }
    else
    {
        //Color key image
        SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );

        //Create texture from surface pixels
        newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
        if( newTexture == NULL )
        {
            printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
        }
        else
        {
            //Get image dimensions
            mWidth = loadedSurface->w;
            mHeight = loadedSurface->h;
        }

        //Get rid of old loaded surface
        SDL_FreeSurface( loadedSurface );
    }

    //Return success
    mTexture = newTexture;
    return mTexture != NULL;
}

#ifdef _SDL_TTF_H
bool LTexture::loadFromRenderedText( std::string textureText, SDL_Color textColor )
{
    //Get rid of preexisting texture
    free();

    //Render text surface
    SDL_Surface* textSurface = TTF_RenderText_Solid( gFont, textureText.c_str(), textColor );
    if( textSurface != NULL )
    {
        //Create texture from surface pixels
        mTexture = SDL_CreateTextureFromSurface( gRenderer, textSurface );
        if( mTexture == NULL )
        {
            printf( "Unable to create texture from rendered text! SDL Error: %s\n", SDL_GetError() );
        }
        else
        {
            //Get image dimensions
            mWidth = textSurface->w;
            mHeight = textSurface->h;
        }

        //Get rid of old surface
        SDL_FreeSurface( textSurface );
    }
    else
    {
        printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
    }


    //Return success
    return mTexture != NULL;
}
#endif

void LTexture::free()
{
    //Free texture if it exists
    if( mTexture != NULL )
    {
        SDL_DestroyTexture( mTexture );
        mTexture = NULL;
        mWidth = 0;
        mHeight = 0;
    }
}

void LTexture::setColor( Uint8 red, Uint8 green, Uint8 blue )
{
    //Modulate texture rgb
    SDL_SetTextureColorMod( mTexture, red, green, blue );
}

void LTexture::setBlendMode( SDL_BlendMode blending )
{
    //Set blending function
    SDL_SetTextureBlendMode( mTexture, blending );
}

void LTexture::setAlpha( Uint8 alpha )
{
    //Modulate texture alpha
    SDL_SetTextureAlphaMod( mTexture, alpha );
}

void LTexture::render( int x, int y, SDL_Rect* clip, double angle, SDL_Point* center, SDL_RendererFlip flip )
{
    //Set rendering space and render to screen
    SDL_Rect renderQuad = { x, y, mWidth, mHeight };

    //Set clip rendering dimensions
    if( clip != NULL )
    {
        renderQuad.w = clip->w;
        renderQuad.h = clip->h;
    }

    //Render to screen
    SDL_RenderCopyEx( gRenderer, mTexture, clip, &renderQuad, angle, center, flip );
}

int LTexture::getWidth()
{
    return mWidth;
}

int LTexture::getHeight()
{
    return mHeight;
}

bool init()
{
    bool success = true;

    //Initialize SDL
    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
        success = false;
    }
    else
    {
        //Enable VSync
        if(!SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"))
        {
            printf("Warning: VSync not enabled!");
        }
        //Set texture filtering to linear
        if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
        {
            printf( "Warning: Linear texture filtering not enabled!" );
        }
    }

    //Create window
    gWindow = SDL_CreateWindow("Dungeon Dash", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
    if (gWindow == NULL)
    {
        printf("SDL could not create window! SDL Error: %s\n", SDL_GetError());
        success = false;
    }
    else
    {
        //Create renderer for window
        gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
        if (gRenderer == NULL)
        {
            printf("SDL could not create renderer! SDL Error: %s\n", SDL_GetError());
            success = false;
        }
        else
        {
            //Initialize renderer color
            SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );

            //Initialize PNG loading
            int imgFlags = IMG_INIT_PNG;
            if( !( IMG_Init( imgFlags ) & imgFlags ) )
            {
                printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
                success = false;
            }
        }
    }

    return success;
}

int main(int argc, char* args[])
{

    if(!init())
    {
        printf("SDL could not initialize!\n");
    }
    else
    {

        bool quit = false;
        SDL_Event e; //Event handler

        //Load all textures
        LTexture boltTexture("graphics/bolt.png");
        LTexture burst1Texture("graphics/burst1.png");
        LTexture burst2Texture("graphics/burst2.png");
        LTexture chestTexture("graphics/chest.png");
        LTexture coinTexture("graphics/coin.png");
        LTexture emptyTileTexture("graphics/emptyTile.png");
        LTexture floorTileTexture("graphics/floorTile.png");
        LTexture healthPadTexture("graphics/healthPad.png");
        LTexture keyTexture("graphics/key.png");
        LTexture snakeDown1Texture("graphics/snakeDown1.png");
        LTexture snakeDown2Texture("graphics/snakeDown2.png");
        LTexture snakeLeft1Texture("graphics/snakeLeft1.png");
        LTexture snakeLeft2Texture("graphics/snakeLeft2.png");
        LTexture snakeRight1Texture("graphics/snakeRight1.png");
        LTexture snakeRight2Texture("graphics/snakeRight2.png");
        LTexture snakeUp1Texture("graphics/snakeUp1.png");
        LTexture snakeUp2Texture("graphics/snakeUp2.png");
        LTexture spiderDown1Texture("graphics/spiderDown1.png");
        LTexture spiderDown2Texture("graphics/spiderDown2.png");
        LTexture spiderLeft1Texture("graphics/spiderLeft1.png");
        LTexture spiderLeft2Texture("graphics/spiderLeft2.png");
        LTexture spiderRight1Texture("graphics/spiderRight1.png");
        LTexture spiderRight2Texture("graphics/spiderRight2.png");
        LTexture spiderUp1Texture("graphics/spiderUp1.png");
        LTexture spiderUp2Texture("graphics/spiderUp2.png");
        LTexture teleportPadTexture("graphics/teleportPad.png");
        LTexture upgradePadTexture("graphics/upgradePad.png");
        LTexture wallTileDownTexture("graphics/wallTileDown.png");
        LTexture wallTileLeftTexture("graphics/wallTileLeft.png");
        LTexture wallTileRightTexture("graphics/wallTileRight.png");
        LTexture wallTileUpTexture("graphics/wallTileUp.png");
        LTexture wizardDown1Texture("graphics/wizardDown1.png");
        LTexture wizardDown2Texture("graphics/wizardDown2.png");
        LTexture wizardLeft1Texture("graphics/wizardLeft1.png");
        LTexture wizardLeft2Texture("graphics/wizardLeft2.png");
        LTexture wizardRight1Texture("graphics/wizardRight1.png");
        LTexture wizardRight2Texture("graphics/wizardRight2.png");
        LTexture wizardUp1Texture("graphics/wizardUp1.png");
        LTexture wizardUp2Texture("graphics/wizardUp2.png");

        //Main player
        Entity player1(20);
        player1.mCurrentTexture = &wizardDown1Texture;

        //Main loop
        while(!quit)
        {
            //Event loop
            while(SDL_PollEvent(&e) != 0)
            {
                if(e.type == SDL_QUIT)
                {
                    quit = true;
                }
            }

            //Clear screen
            SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 255);
            SDL_RenderClear(gRenderer);

            player1.render(0, 0);

            //Update screen
            SDL_RenderPresent(gRenderer);
        }

        //If script reaches here, user has exited; quit program

        //Free loaded images
        boltTexture.free();
        burst1Texture.free();
        burst2Texture.free();
        chestTexture.free();
        coinTexture.free();
        emptyTileTexture.free();
        floorTileTexture.free();
        healthPadTexture.free();
        keyTexture.free();
        snakeDown1Texture.free();
        snakeDown2Texture.free();
        snakeLeft1Texture.free();
        snakeLeft2Texture.free();
        snakeRight1Texture.free();
        snakeRight2Texture.free();
        snakeUp1Texture.free();
        snakeUp2Texture.free();
        spiderDown1Texture.free();
        spiderDown2Texture.free();
        spiderLeft1Texture.free();
        spiderLeft2Texture.free();
        spiderRight1Texture.free();
        spiderRight2Texture.free();
        spiderUp1Texture.free();
        spiderUp2Texture.free();
        teleportPadTexture.free();
        upgradePadTexture.free();
        wallTileDownTexture.free();
        wallTileLeftTexture.free();
        wallTileRightTexture.free();
        wallTileUpTexture.free();
        wizardDown1Texture.free();
        wizardDown2Texture.free();
        wizardLeft1Texture.free();
        wizardLeft2Texture.free();
        wizardRight1Texture.free();
        wizardRight2Texture.free();
        wizardUp1Texture.free();
        wizardUp2Texture.free();

        //Destroy window
        SDL_DestroyRenderer( gRenderer );
        SDL_DestroyWindow( gWindow );
        gWindow = NULL;
        gRenderer = NULL;

        //Quit SDL subsystems
        IMG_Quit();
        SDL_Quit();
    }
}

在此先感谢您的帮助。

我发现了这个问题,因为我从SDL_GetError中得到了相同的错误。 此处的答案表明在没有错误的情况下SDL_GetError可能会说“ Invalid Renderer”是有信息的。 仅在最后一个调用的SDL函数实际上指示错误的情况下,才可以依赖SDL_GetError。

但是,我的情况略有不同。 我正在调用SDL_WaitEventTimeout,该函数返回1表示由于事件而提前返回,或者返回0表示到期的计时器或错误,并使用户依靠SDL_GetError来确定是否发生了错误。 在这种情况下,在调用SDL_WaitEventTimeout之前先调用SDL_ClearError至关重要。 另外,如果没有错误,SDL_GetError将返回一个空字符串,而不是一个空指针。

int frameRate = 30;
SDL_Event e;

SDL_ClearError();
int ret = SDL_WaitEventTimeout( &e, 1000/frameRate );

if ( ret )
{
    // event received, process events
}
else
{
    // timeout or error; have to check
    const char *s = SDL_GetError();
    if ( *s )
    {
        cout << "SDL_WaitEventTimeout: " << s << endl;
    }
    else
    {
        // normal timeout, do normal actions
    }
}

这似乎是SDL_WaitEventTimeout设计中的一个缺陷,它浪费了大部分的返回值空间。 当它导致错误时,它实际上应该返回-1,在超时时它应该返回0,并且在事件发生时还剩下毫秒数。 我怀疑它实际上已被弃用为帧计时器,并且我将不得不依赖SDL_PollEvent进行事件,并且必须使用OS /硬件本地计时器进行帧同步,这浪费了SDL的可移植性。

引发错误的那一行是创建渲染器的那一行,但是可以忽略该错误(因为它不会返回NULL)。 SDL使用宏来检查渲染器是否正常,如果不正常,它将自动设置该错误字符串。 可能为时过早。 但是,这与您的问题无关。

在这里你的问题是因为在LTexture构造函数调用loadFromFile()其中规定mWidthmHeight正常。 然后,将它们再次设置为0,使renderQuad没有区域,从而使纹理不渲染。

在此之前将它们设置为0,或者甚至更好的是,在初始化程序列表中将它们设置为0:

LTexture::LTexture(std::string path)
: mTexture(NULL), mWidth(0), mHeight(0)
{
  loadFromFile(path);
}

另外, LTexture类具有一个名为free的方法,尽管它不是保留名称,但可能会引起同事的困惑(就像对我的做法一样:),您可以考虑使用其他名称。

尝试更改传递给SDL_CreateRenderer()的标志。 我遇到了与您相同的问题,最终我发现在我的机器上,SDL在硬件加速渲染(碰巧是默认设置)方面遇到了麻烦。 尝试将SDL_RENDERER_ACCELERATED更改为SDL_RENDERER_SOFTWARE ,看看是否有帮助。

此外,每当您有一个要修复的棘手的错误时,请分解该问题。 你的代码庞大 (堆栈溢出)量在这里,并且有你剪下来,只是渲染位,然后(1)其他人可能已经能够更快地帮助你,(2),你可能已经能够解决自己解决问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM