SDL_Renderer 用作全局变量,但如果在 main 中声明则不会,而是传递给需要它的函数
SDL_Renderer works as global variable, but not if declared in main, and passed to the functions that require it instead
我一直在回顾一些 SDL 教程,我为了练习做了一段时间 pointers/references,但我遇到了一些问题。
如果我全局声明 SDL_Renderer 一切正常,但如果我尝试在 main 中声明它,并将渲染器传递给需要它的函数,我最终会得到一个 SDL_Error 说“渲染器无效”。
什么有效:
...
// Global vars
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
SDL_Rect gSpriteClips[ 4 ];
LTexture gSpriteSheetTexture;
...
// called from main after SDL initialization
bool loadMedia()
{
bool success = true;
//Load sprite sheet texture
if( !gSpriteSheetTexture.loadFromFile( gRenderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
什么不起作用:
...
bool init( SDL_Window* window, SDL_Renderer* renderer, const int SCREEN_WIDTH, const int SCREEN_HEIGHT )
{
...
}
...
bool load_media( SDL_Renderer* renderer, LTexture& sprite_sheet_texture, SDL_Rect* sprite_clips )
{
bool success = true;
//Load sprite sheet texture
if( !sprite_sheet_texture.loadFromFile( renderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
int main(int argc, char* args[])
{
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect sprite_clips[ 4 ];
LTexture sprite_sheet_texture;
if( !init( window, renderer, SCREEN_WIDTH, SCREEN_HEIGHT ) )
{
std::cout << "Failed to initialize!\n";
}
else
{
if( !load_media( renderer, sprite_sheet_texture, sprite_clips ) )
{
std::cout << "Failed to load media!\n";
}
...
纹理class:(两个版本的文件相同)
bool LTexture::loadFromFile( SDL_Renderer* gRenderer, const 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 )
{
std::cout << "Unable to load image! SDL_Image error: " << IMG_GetError() << std::endl;
}
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 ); <-- POINT OF FAILURE
if( newTexture == NULL )
{
std::cout << "Unable to create texture! SDL error: " << SDL_GetError() << std::endl; <-- THE ERROR I GET
}
...
在我看来,SDL_CreateTextureFromSurface 需要一个指向 SDL_Renderer 的指针,这正是我要传递的内容。我不明白为什么它在全球范围内声明或在 main 中声明很重要。它应该仍然只是我指向某处的一大块内存。
我知道我一定是把它传递错了,但我不知道如何正确地做,而且我尝试过的一切都产生了同样的错误(将指针作为引用传递,作为指向指针的指针等。 ).
旁注:我知道我可以全局声明它或创建一个单例并完成它,但这对我来说更像是一个学习练习 - 所以重点是理解 pointer/reference 方面的问题。
在第二个代码段中,如果 init
更改变量 renderer
,它只会更改变量的本地副本。它不会改变函数main
中的原始变量renderer
。这是因为你传递的是变量by value. If you instead pass it by pointer or by reference,你也会修改原来变量的值。这样,您的程序的行为方式将与您的全局变量版本相同。
请注意,为了通过指针将指针传递给另一个函数,您将需要一个指向指针的指针。在您的情况下,您将需要 SDL_Renderer **
.
根据 Andreas Wenzel 的回答和建议,我现在有了一个可行的解决方案。我以为我是通过指针传递的,而实际上我是通过值传递的。通过将指针传递给指针,它会按预期工作。
我在下面包含了一些片段,以显示与原始问题中代码的不同之处。
int main(int argc, char* args[])
{
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect sprite_clips[ 4 ];
LTexture sprite_sheet_texture;
if( !init( &window, &renderer, SCREEN_WIDTH, SCREEN_HEIGHT ) )
{
std::cout << "Failed to initialize!\n";
}
else
{
if( !load_media( &renderer, sprite_sheet_texture, sprite_clips ) )
{
std::cout << "Failed to load media!\n";
}
...
bool init( SDL_Window** window, SDL_Renderer** renderer, const int SCREEN_WIDTH, const int SCREEN_HEIGHT )
{
bool success = true;
// initialize SDL
if( SDL_Init( SDL_INIT_VIDEO) < 0 )
{
std::cout << "SDL could not initialize! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
{
std::cout << "Warning: Linear texture filtering not enabled!\n";
}
// Create window
*window = SDL_CreateWindow(
"SDL Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN
);
if( window == NULL )
{
std::cout << "Window could not be created! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
// Create renderer for window
*renderer = SDL_CreateRenderer( *window, -1, SDL_RENDERER_ACCELERATED );
if( renderer == NULL )
{
std::cout << "Renderer could not be created! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
...
bool load_media( SDL_Renderer** renderer, LTexture& sprite_sheet_texture, SDL_Rect* sprite_clips )
{
bool success = true;
//Load sprite sheet texture
if( !sprite_sheet_texture.loadFromFile( *renderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
void close( SDL_Window** window, SDL_Renderer** renderer )
{
//Destroy Window
SDL_DestroyRenderer( *renderer );
SDL_DestroyWindow( *window );
*window = NULL;
*renderer = NULL;
IMG_Quit();
SDL_Quit();
}
我一直在回顾一些 SDL 教程,我为了练习做了一段时间 pointers/references,但我遇到了一些问题。
如果我全局声明 SDL_Renderer 一切正常,但如果我尝试在 main 中声明它,并将渲染器传递给需要它的函数,我最终会得到一个 SDL_Error 说“渲染器无效”。
什么有效:
...
// Global vars
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
SDL_Rect gSpriteClips[ 4 ];
LTexture gSpriteSheetTexture;
...
// called from main after SDL initialization
bool loadMedia()
{
bool success = true;
//Load sprite sheet texture
if( !gSpriteSheetTexture.loadFromFile( gRenderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
什么不起作用:
...
bool init( SDL_Window* window, SDL_Renderer* renderer, const int SCREEN_WIDTH, const int SCREEN_HEIGHT )
{
...
}
...
bool load_media( SDL_Renderer* renderer, LTexture& sprite_sheet_texture, SDL_Rect* sprite_clips )
{
bool success = true;
//Load sprite sheet texture
if( !sprite_sheet_texture.loadFromFile( renderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
int main(int argc, char* args[])
{
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect sprite_clips[ 4 ];
LTexture sprite_sheet_texture;
if( !init( window, renderer, SCREEN_WIDTH, SCREEN_HEIGHT ) )
{
std::cout << "Failed to initialize!\n";
}
else
{
if( !load_media( renderer, sprite_sheet_texture, sprite_clips ) )
{
std::cout << "Failed to load media!\n";
}
...
纹理class:(两个版本的文件相同)
bool LTexture::loadFromFile( SDL_Renderer* gRenderer, const 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 )
{
std::cout << "Unable to load image! SDL_Image error: " << IMG_GetError() << std::endl;
}
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 ); <-- POINT OF FAILURE
if( newTexture == NULL )
{
std::cout << "Unable to create texture! SDL error: " << SDL_GetError() << std::endl; <-- THE ERROR I GET
}
...
在我看来,SDL_CreateTextureFromSurface 需要一个指向 SDL_Renderer 的指针,这正是我要传递的内容。我不明白为什么它在全球范围内声明或在 main 中声明很重要。它应该仍然只是我指向某处的一大块内存。 我知道我一定是把它传递错了,但我不知道如何正确地做,而且我尝试过的一切都产生了同样的错误(将指针作为引用传递,作为指向指针的指针等。 ).
旁注:我知道我可以全局声明它或创建一个单例并完成它,但这对我来说更像是一个学习练习 - 所以重点是理解 pointer/reference 方面的问题。
在第二个代码段中,如果 init
更改变量 renderer
,它只会更改变量的本地副本。它不会改变函数main
中的原始变量renderer
。这是因为你传递的是变量by value. If you instead pass it by pointer or by reference,你也会修改原来变量的值。这样,您的程序的行为方式将与您的全局变量版本相同。
请注意,为了通过指针将指针传递给另一个函数,您将需要一个指向指针的指针。在您的情况下,您将需要 SDL_Renderer **
.
根据 Andreas Wenzel 的回答和建议,我现在有了一个可行的解决方案。我以为我是通过指针传递的,而实际上我是通过值传递的。通过将指针传递给指针,它会按预期工作。
我在下面包含了一些片段,以显示与原始问题中代码的不同之处。
int main(int argc, char* args[])
{
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect sprite_clips[ 4 ];
LTexture sprite_sheet_texture;
if( !init( &window, &renderer, SCREEN_WIDTH, SCREEN_HEIGHT ) )
{
std::cout << "Failed to initialize!\n";
}
else
{
if( !load_media( &renderer, sprite_sheet_texture, sprite_clips ) )
{
std::cout << "Failed to load media!\n";
}
...
bool init( SDL_Window** window, SDL_Renderer** renderer, const int SCREEN_WIDTH, const int SCREEN_HEIGHT )
{
bool success = true;
// initialize SDL
if( SDL_Init( SDL_INIT_VIDEO) < 0 )
{
std::cout << "SDL could not initialize! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) )
{
std::cout << "Warning: Linear texture filtering not enabled!\n";
}
// Create window
*window = SDL_CreateWindow(
"SDL Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN
);
if( window == NULL )
{
std::cout << "Window could not be created! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
else
{
// Create renderer for window
*renderer = SDL_CreateRenderer( *window, -1, SDL_RENDERER_ACCELERATED );
if( renderer == NULL )
{
std::cout << "Renderer could not be created! SDL error: " << SDL_GetError() << std::endl;
success = false;
}
...
bool load_media( SDL_Renderer** renderer, LTexture& sprite_sheet_texture, SDL_Rect* sprite_clips )
{
bool success = true;
//Load sprite sheet texture
if( !sprite_sheet_texture.loadFromFile( *renderer, "img/dots.png" ) )
{
printf( "Failed to load sprite sheet texture!\n" );
success = false;
}
...
void close( SDL_Window** window, SDL_Renderer** renderer )
{
//Destroy Window
SDL_DestroyRenderer( *renderer );
SDL_DestroyWindow( *window );
*window = NULL;
*renderer = NULL;
IMG_Quit();
SDL_Quit();
}