SDL 2.0 - 无效的渲染器错误

时间:2014-02-28 03:05:08

标签: c++ sdl-2

我对于试图解决这个问题感到非常沮丧。我一直关注http://lazyfoo.net/tutorials/SDL/index.php。然后我尝试用SDL2开始制作游戏,但很快就遇到了这个错误:我无法向屏幕渲染任何东西。屏幕弹出,我可以正确清除它。如果我调用SDL_GetError(),则输出为“Invalid Renderer”。我检查了代码,试图找出可能导致此错误的位置,并在互联网上搜索无济于事。可能导致问题的是我有一个具有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();
    }
}

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:4)

我发现了这个问题,因为我从SDL_GetError得到了同样的错误。这里的答案表明SDL_GetError可能会说&#34;无效的渲染器&#34;在没有错误的情况下提供信息。只有在调用的最后一个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的可移植性。

答案 1 :(得分:3)

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

您的问题是因为在LTexture构造函数中,您调用了loadFromFile(),它正确地设置了mWidthmHeight。然后再次将它们设置为0,使renderQuad没有区域,从而使纹理不会渲染。

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

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

此外,LTexture类有一个名为free的方法,虽然不是保留名称,但可能会导致同事混淆(就像我一样:),你可能会考虑不同名。

答案 2 :(得分:0)

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

此外,每当您遇到特别棘手的错误时,请尝试解决问题。这里有一个巨大的(用于Stack Overflow)代码量,并且你把它减少到只有渲染位然后(1)其他人可能能够更快地帮助你(2)你可能已经能够自己解决这个问题了。