SDL 2.0-无效的呈现程序错误

SDL 2.0 - Invalid Renderer Error

本文关键字:程序 错误 无效 SDL      更新时间:2023-10-16

我只是对试图弄清楚这一点感到太沮丧了。我一直在关注http://lazyfoo.net/tutorials/SDL/index.php.然后我试图开始用SDL2制作游戏,但很快就遇到了这个错误:我无法在屏幕上渲染任何内容。屏幕弹出,我可以正确地清除所有内容。如果我调用SDL_GetError(),则输出为"无效渲染器"。我检查了代码,试图找出这个错误的原因,并在互联网上搜索了一下,但没有结果。可能导致问题的原因是我有一个类,它有一个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: %sn", 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: %sn", 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: %sn", 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: %sn", 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: %sn", 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: %sn", 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: %sn", 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: %sn", 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在没有错误的情况下可能会说"无效的呈现器",这是有信息的。SDL_GetError只能在调用的最后一个SDL函数实际指示错误的情况下使用。

不过,我的情况略有不同。我调用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,或者更好的是,在初始值设定项列表中将它们设置为:

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

此外,LTexture类有一个名为free的方法,虽然它不是保留名称,但可能会在您的同事中引起混淆(就像它对我所做的那样:),您可能会考虑另一个名称。

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

此外,每当你有一个特别棘手的bug要修复时,就把问题分解。您在这里有大量的(用于堆栈溢出)代码,如果您将其减少到仅渲染位,则(1)其他人可能能够更快地帮助您,(2)您可能能够自己解决问题。