В настоящее время я разрабатываю приложение с графическим интерфейсом на C ++ и SDL2. Я столкнулся с очень странным поведением при попытке рендеринга некоторых моих текстур. Я использую пользовательскую текстурную обёртку, основанную на уроках Lazy Foo (http://lazyfoo.net/tutorials/SDL/43_render_to_texture/index.php), которая называется Texture, построенная поверх класса SDL текстуры SDL_Texture. Обычно, когда я создаю текстуру с помощью моего конструктора по умолчанию "Texture ()", а затем попробуйте отобразить его на экране, все работает как задумано. Однако в трех отдельных случаях у меня получилось очень странное поведение. В проблемных случаях он часто рисует текстуру из другого объекта и получается искаженным, иногда просто не рисует вообще, и часто беспорядочно мигает, как будто средство визуализации рисует его только каждые несколько кадров. При многократном запуске текстуры всегда испорчены, но какие симптомы появляются, например, мигает ли он или даже отображается при всех изменениях без перекомпиляции кода. Нет ошибок или предупреждений компилятора, и я не получаю вывод stderr во время работы. Что странно, если я устанавливаю объект как указатель и создаю его экземпляр с помощью "new Texture ()", все работает точно так, как должно .
К счастью, я нашел решение своей проблемы с помощью указателей, но я могу предположить, что причиной этого является только одна из трех: есть ошибка в библиотеке SDL2 (маловероятно), есть ошибка в моем классе текстур, или Мне не хватает какой-то очень фундаментальной концепции того, как объекты обрабатываются в C ++. В любом из этих случаев он вернется, чтобы укусить меня, если я попытаюсь игнорировать это.
Я занимаюсь разработкой под Linux (Ubuntu 16.04) и компилирую с G ++.
Я включу некоторый код для одного из проблемных случаев ниже. В этом случае я создавал класс «HistoryEntry», который мог бы взять некоторые атрибуты и нарисовать себя в произвольных X и Y. Все объекты текстуры атрибута HistoryEntry, кроме timeText, перепутались, и когда они действительно рисуют, они, кажется, рисуют искаженную версию. текстуры timeText. Похоже, они сохранили свои собственные значения ширины и высоты, но их текстура перезаписывалась, когда я загружал timeText. Однако, насколько я понимаю, конструктор всегда будет генерировать совершенно новый объект, и особенно странно, если копируются только некоторые его атрибуты. Все идет гладко, если я изменю все атрибутные объекты текстуры на указатели, которые указывают на указанные объекты текстуры.
Конструктор текстур и функция загрузки:
Texture::Texture()
{
//Initialize
mTexture = NULL;
mWidth = 0;
mHeight = 0;
}
bool Texture::loadText( std::string textureText, SDL_Color textColor, TTF_Font* gFont)
{
//Get rid of preexisting texture
free();
//Render text surface
SDL_Surface* textSurface = TTF_RenderText_Blended( gFont, textureText.c_str(), textColor );
if( textSurface == NULL )
{
printf( "Unable to render text surface! SDL_ttf Error: %s\n", TTF_GetError() );
}
else
{
//Create texture from surface pixels
mTexture = SDL_CreateTextureFromSurface( getRenderer(), 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 );
}
//Return success
return mTexture != NULL;
}
Метод рендеринга текстур:
void Texture::render( int x, int y, int anchor, SDL_Rect* clip )
{
SDL_Rect renderQuad;
//Set rendering space and render to screen
if(anchor == MIDDLE_CENTER){
renderQuad = { x - mWidth/2, y - mHeight/2, mWidth, mHeight };
}else if(anchor == MIDDLE_LEFT){
renderQuad = { x, y - mHeight/2, mWidth, mHeight };
}else if(anchor == MIDDLE_RIGHT){
renderQuad = { x - mWidth, y - mHeight/2, mWidth, mHeight };
}else{
renderQuad = { x, y, mWidth, mHeight };
}
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}
//Render to screen
SDL_RenderCopy( getRenderer(), mTexture, clip, &renderQuad );
}
HistoryEntry класс:
#include <SDL.h>
#include <SDL_image.h>
#include <string>
#include "auxx.h"
#include "texture.h"
#include "history_entry.h"
HistoryEntry::HistoryEntry(){
}
// Constructor for notifications
HistoryEntry::HistoryEntry(int t, std::string n, std::string v)
{
//Atributes
type = t;
eventTime = GetTimer();
name = Texture();
name.loadText(n, defaultColor, defaultFont);
value = Texture();
value.loadText(v, defaultColor, defaultFont);
//code = Texture();
//code.loadText(c, defaultColor, defaultFontSmall);
//icon = i;
timeText = Texture();
}
// Constuctor for error and warnings
HistoryEntry::HistoryEntry(int t, std::string n, std::string c, Texture i)
{
//Atributes
type = t;
eventTime = GetTimer();
name = Texture();
name.loadText(n, defaultColor, defaultFont);
//value = Texture();
//value.loadText(v, defaultColor, defaultFont);
code = Texture();
code.loadText(c, defaultColor, defaultFontSmall);
icon = i;
timeText = Texture();
}
void HistoryEntry::draw(SDL_Renderer* renderer, int x, int y){
if(type == NOTIFICATION_ENTRY){
name.render(x + 7, y + 15);
value.render(x + 620, y + 15);
// Set up time text
// Seconds
if(timeSince() < 60){
timeBuff = std::to_string(timeSince()) + " sec ago";
timeText.loadText(timeBuff , defaultColor, defaultFont);
}
// Minutes
else{
timeBuff = std::to_string(timeSince()/60) + " min ago";
timeText.loadText(timeBuff , defaultColor, defaultFont);
}
timeText.render(x + 440, y + 15);
}else{
icon.render(x + 3, y + 13);
name.render(x + 44, y + 15);
code.render(x + 44, y + 45);
//value.render(x + 620, y + 15);
// Set up time text
// Seconds
if(timeSince() < 60){
timeBuff = std::to_string(timeSince()) + " sec ago";
timeText.loadText(timeBuff , defaultColor, defaultFont);
}
// Minutes
else{
timeBuff = std::to_string(timeSince()/60) + " min ago";
timeText.loadText(timeBuff , defaultColor, defaultFont);
}
timeText.render(x + 440, y + 15);
}
}
int HistoryEntry::getHeight(){
if(type = NOTIFICATION_ENTRY){
return 63;
}else{
return 89;
}
}
int HistoryEntry::timeSince(){
return GetTimePassedSeconds(eventTime);
}
Часть функции отображения, которая вызывает чертеж:
void DrawGraphics()
{
SDL_Renderer *renderer = getRenderer();
//Clear screen
SDL_SetRenderDrawColor( renderer, 0xFF, 0xFF, 0xFF, 0xFF );
SDL_RenderClear( renderer );
...
// Draw history if it is active
if(history_active){
historyBackground.render(480, 79);
}
// Y position of first history entry
int rowY = 134;
// Draw history entries
if(history_active){
// Set color for history lines
SDL_SetRenderDrawColor(renderer, 52, 64, 79, 0);
for(int i = 0; i < history.size(); i++){
history[i].draw(renderer, 495, rowY);
// Increment the y value based on entry size
if(history[i].type == NOTIFICATION_ENTRY){
rowY += 63;
}else{
rowY += 89;
}
// Draw lines
SDL_RenderDrawLine(renderer, 495, rowY - 1, 1287, rowY - 1);
}
}
//Update screen
SDL_RenderPresent( renderer );
}