使用复制构造函数后 SDL 纹理不渲染
SDL Texture not rendering after use of copy constructor
我正在制作一个使用 SDL 渲染图形的基本程序。我有两个处理渲染的 classes:
纹理 class(加载并渲染 SDL_textures)
//Texture warpper class
class LTexture
{
private:
//The actual texture
SDL_Texture* mTexture;
//Image demensions
int mWidth;
int mHeight;
public:
//Initializes/Deallocates variables
LTexture();
~LTexture();
LTexture(const LTexture &rhs);
//Loads image at specified path
bool loadFromFile(std::string path);
//Deallocates texture
void free();
//Renders texture at given point
void render(int x, int y);
//Gets image dimensions
int getWidth();
int getHeight();
};
LTexture::LTexture()
{
//Initialize
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
LTexture::~LTexture()
{
//Deallocate
free();
}
LTexture::LTexture(const LTexture &rhs)
{
mTexture = rhs.mTexture;
mWidth = rhs.mWidth;
mHeight = rhs.mHeight;
}
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
{
//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;
}
void LTexture::free()
{
//Free Texture if it exists
if (mTexture != NULL)
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
void LTexture::render(int x, int y)
{
//Set rendering space and render to screen
SDL_Rect renderQuad = { x, y, mWidth, mHeight };
SDL_RenderCopy(gRenderer, mTexture, NULL, &renderQuad);
printf("Rendering...\n");
if (mTexture == NULL)
{
printf("No texture loaded!\n");
}
else
{
printf("Texture loaded! %s\n", mTexture);
}
}
int LTexture::getWidth()
{
return mWidth;
}
int LTexture::getHeight()
{
return mHeight;
}
和一个按钮 class(这应该可以更容易地在与按钮状态相关联的不同纹理之间切换。每个对象应该在按钮内有 3 个纹理对象)。
声明:
//Class for buttons and chips
class Button
{
public:
//Initializes internal variables
Button();
//Handles mouse events
void handleEvent(SDL_Event* e);
//Render buttons
void render();
//Sets top left position
void setPosition(int x, int y);
//Gets image dimensions
void setWidth(int w);
void setHeight(int h);
//Set button status
void setButtonAction(buttonAction action);
//Get button status
buttonStatus getButtonStatus();
//Perform button action !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!FIXME::HAVEN'T DEFINED!!!!!!!!!!!!!!!!!!!!!!!!!!!!1!!
void activateButton(buttonAction action);
void setTextures(LTexture out, LTexture over, LTexture down);
private:
//Top left position
SDL_Point mPosition;
//Currently used global image
buttonStatus mButtonStatus;
//What happens if button is pressed
buttonAction mButtonAction;
//Width and height
int mWidth;
int mHeight;
//Textures
LTexture mOut;
LTexture mOver;
LTexture mDown;
};
Button::Button()
{
mPosition.x = 0;
mPosition.y = 0;
mWidth = 0;
mHeight = 0;
mButtonStatus = MOUSE_OUT;
}
void Button::setPosition(int x, int y)
{
mPosition.x = x;
mPosition.y = y;
}
void Button::handleEvent(SDL_Event* e)
{
bool mInside = true;
//If mouse event happened
if (e->type == SDL_MOUSEBUTTONDOWN || e->type == SDL_MOUSEMOTION)
{
//Get mouse position
int x, y;
SDL_GetMouseState(&x, &y);
//Mouse is left of the button
if (x < mPosition.x)
{
mInside = false;
}
//Mouse is right of button
else if (x > mPosition.x + mWidth)
{
mInside = false;
}
//Mouse is above button
else if (y < mPosition.y)
{
mInside = false;
}
//Mouse is below button
else if (y > mPosition.y + mHeight)
{
mInside = false;
}
//Logic\
//Mouse is outside of button
if (!mInside)
{
mButtonStatus = MOUSE_OUT;
}
//Mouse is inside of button
else
{
switch (e->type)
{
case SDL_MOUSEMOTION:
mButtonStatus = MOUSE_OVER;
break;
case SDL_MOUSEBUTTONDOWN:
mButtonStatus = MOUSE_BUTTON_DOWN;
break;
}
}
}
}
void Button::render()
{
switch (mButtonStatus)
{
case MOUSE_OUT:
mOut.render(mPosition.x, mPosition.y);
printf("Out rendered\n");
break;
case MOUSE_OVER:
mOver.render(mPosition.x, mPosition.y);
printf("Over rendered\n");
break;
case MOUSE_BUTTON_DOWN:
mDown.render(mPosition.x, mPosition.y);
printf("Down rendered\n");
break;
}
}
void Button::setWidth(int w)
{
mWidth = w;
}
void Button::setHeight(int h)
{
mHeight = h;
}
void Button::setButtonAction(buttonAction action)
{
mButtonAction = action;
}
buttonStatus Button::getButtonStatus()
{
return mButtonStatus;
}
void Button::setTextures(LTexture out, LTexture over, LTexture down)
{
mOut = out;
mOver = over;
mDown = down;
}
不幸的是,当我尝试使用复制构造函数将 SDL_Texture 值从原始纹理传递给按钮私有纹理时,它没有传递任何值,但仍然认为它不是 "NULL"
我发现这段代码有两个问题。
第一个是在 LTexture
复制构造函数中,您只将 指针 复制到 SDL_Texture
。这称为浅拷贝。然后,在 LTexture
的析构函数中调用 free()
,它会删除 SDL_Texture
。这很糟糕,因为这意味着 LTexture
的任何副本现在都有指向已删除纹理的指针,因此它们将不再起作用。这里最好的两个解决方案是使用名为 shared_ptr
的 c++11 class 来存储纹理,这将防止它被删除,或者实际复制纹理并指向新的(深拷贝)。为了进行测试,您可以尝试在 free()
.
中注释掉对 SDL_DestroyTexture
的调用
此外,您忘记实现赋值运算符。目前它的行为就像复制构造函数(因为你所做的只是一个浅拷贝),但如果你把它做成一个深拷贝,你也必须实现它。
我正在制作一个使用 SDL 渲染图形的基本程序。我有两个处理渲染的 classes:
纹理 class(加载并渲染 SDL_textures)
//Texture warpper class
class LTexture
{
private:
//The actual texture
SDL_Texture* mTexture;
//Image demensions
int mWidth;
int mHeight;
public:
//Initializes/Deallocates variables
LTexture();
~LTexture();
LTexture(const LTexture &rhs);
//Loads image at specified path
bool loadFromFile(std::string path);
//Deallocates texture
void free();
//Renders texture at given point
void render(int x, int y);
//Gets image dimensions
int getWidth();
int getHeight();
};
LTexture::LTexture()
{
//Initialize
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
LTexture::~LTexture()
{
//Deallocate
free();
}
LTexture::LTexture(const LTexture &rhs)
{
mTexture = rhs.mTexture;
mWidth = rhs.mWidth;
mHeight = rhs.mHeight;
}
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
{
//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;
}
void LTexture::free()
{
//Free Texture if it exists
if (mTexture != NULL)
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
}
void LTexture::render(int x, int y)
{
//Set rendering space and render to screen
SDL_Rect renderQuad = { x, y, mWidth, mHeight };
SDL_RenderCopy(gRenderer, mTexture, NULL, &renderQuad);
printf("Rendering...\n");
if (mTexture == NULL)
{
printf("No texture loaded!\n");
}
else
{
printf("Texture loaded! %s\n", mTexture);
}
}
int LTexture::getWidth()
{
return mWidth;
}
int LTexture::getHeight()
{
return mHeight;
}
和一个按钮 class(这应该可以更容易地在与按钮状态相关联的不同纹理之间切换。每个对象应该在按钮内有 3 个纹理对象)。
声明:
//Class for buttons and chips
class Button
{
public:
//Initializes internal variables
Button();
//Handles mouse events
void handleEvent(SDL_Event* e);
//Render buttons
void render();
//Sets top left position
void setPosition(int x, int y);
//Gets image dimensions
void setWidth(int w);
void setHeight(int h);
//Set button status
void setButtonAction(buttonAction action);
//Get button status
buttonStatus getButtonStatus();
//Perform button action !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!FIXME::HAVEN'T DEFINED!!!!!!!!!!!!!!!!!!!!!!!!!!!!1!!
void activateButton(buttonAction action);
void setTextures(LTexture out, LTexture over, LTexture down);
private:
//Top left position
SDL_Point mPosition;
//Currently used global image
buttonStatus mButtonStatus;
//What happens if button is pressed
buttonAction mButtonAction;
//Width and height
int mWidth;
int mHeight;
//Textures
LTexture mOut;
LTexture mOver;
LTexture mDown;
};
Button::Button()
{
mPosition.x = 0;
mPosition.y = 0;
mWidth = 0;
mHeight = 0;
mButtonStatus = MOUSE_OUT;
}
void Button::setPosition(int x, int y)
{
mPosition.x = x;
mPosition.y = y;
}
void Button::handleEvent(SDL_Event* e)
{
bool mInside = true;
//If mouse event happened
if (e->type == SDL_MOUSEBUTTONDOWN || e->type == SDL_MOUSEMOTION)
{
//Get mouse position
int x, y;
SDL_GetMouseState(&x, &y);
//Mouse is left of the button
if (x < mPosition.x)
{
mInside = false;
}
//Mouse is right of button
else if (x > mPosition.x + mWidth)
{
mInside = false;
}
//Mouse is above button
else if (y < mPosition.y)
{
mInside = false;
}
//Mouse is below button
else if (y > mPosition.y + mHeight)
{
mInside = false;
}
//Logic\
//Mouse is outside of button
if (!mInside)
{
mButtonStatus = MOUSE_OUT;
}
//Mouse is inside of button
else
{
switch (e->type)
{
case SDL_MOUSEMOTION:
mButtonStatus = MOUSE_OVER;
break;
case SDL_MOUSEBUTTONDOWN:
mButtonStatus = MOUSE_BUTTON_DOWN;
break;
}
}
}
}
void Button::render()
{
switch (mButtonStatus)
{
case MOUSE_OUT:
mOut.render(mPosition.x, mPosition.y);
printf("Out rendered\n");
break;
case MOUSE_OVER:
mOver.render(mPosition.x, mPosition.y);
printf("Over rendered\n");
break;
case MOUSE_BUTTON_DOWN:
mDown.render(mPosition.x, mPosition.y);
printf("Down rendered\n");
break;
}
}
void Button::setWidth(int w)
{
mWidth = w;
}
void Button::setHeight(int h)
{
mHeight = h;
}
void Button::setButtonAction(buttonAction action)
{
mButtonAction = action;
}
buttonStatus Button::getButtonStatus()
{
return mButtonStatus;
}
void Button::setTextures(LTexture out, LTexture over, LTexture down)
{
mOut = out;
mOver = over;
mDown = down;
}
不幸的是,当我尝试使用复制构造函数将 SDL_Texture 值从原始纹理传递给按钮私有纹理时,它没有传递任何值,但仍然认为它不是 "NULL"
我发现这段代码有两个问题。
第一个是在 LTexture
复制构造函数中,您只将 指针 复制到 SDL_Texture
。这称为浅拷贝。然后,在 LTexture
的析构函数中调用 free()
,它会删除 SDL_Texture
。这很糟糕,因为这意味着 LTexture
的任何副本现在都有指向已删除纹理的指针,因此它们将不再起作用。这里最好的两个解决方案是使用名为 shared_ptr
的 c++11 class 来存储纹理,这将防止它被删除,或者实际复制纹理并指向新的(深拷贝)。为了进行测试,您可以尝试在 free()
.
SDL_DestroyTexture
的调用
此外,您忘记实现赋值运算符。目前它的行为就像复制构造函数(因为你所做的只是一个浅拷贝),但如果你把它做成一个深拷贝,你也必须实现它。