Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

sdl2, wycieki pamięci i valgrind

Ostatnio zmodyfikowano 2019-01-28 16:57
Autor Wiadomość
rafallauterbach
Temat założony przez niniejszego użytkownika
sdl2, wycieki pamięci i valgrind
» 2019-01-28 16:35:49
Czy ktoś kiedyś szukał wycieków w programie z SDL za pomocą Valgrind?

Prosiłbym o informację czy popełniam jakiś rażący bład.

Z tego co rozumiem, to program ten wyłapuje gdy próbuję użyć niewłaściwego pointera, ale w połączeniu z SDL-em (SDL2) wyrzuca mi co chwila błedy typu :


==9578== Invalid write of size 4
(... backtrace ...)
==9578==  Address 0x7f2bf6fcb070 is not stack'd, malloc'd or (recently) free'd

Wszędzie gdzie używam "magicznej" funkcji SDLa pointera doo typedefu, które daje mi SDL (konkretnie : typ "SDL_Renderer*") dostaję taki błąd jak powyżej -> funkcje których używam i dostaję błąd tego typu są poniżej...

-1-
C/C++
SDL_RenderPresent( Game::gameRenderer );
//z definicji ->
//SDL_RenderPresent(SDL_Renderer* renderer) : void
//wytworzone tu ->
//Game::gameRenderer = SDL_CreateRenderer( Game::gameWindow, -1, SDL_RENDERER_ACCELERATED );
nie widzę tu mojego błędu, bo używam tylko SDLowych funkcji.

-2-
C/C++
SDL_RenderCopy( renderer, text_text, NULL, & renderQuad );
// ok tego nie chce mi się tłumaczyć, załóżmy że tutaj nawet mój bład, bo jest mi ten błąd obojętny na chwilę obecną

-3-
C/C++
SDL_RenderCopy( gRenderer, mTexture, & clip, & r );
//tutaj swoją drogą -> czy powinienem używać referencji do tymczasowej zmiennej która za moment zniknie? Chyba nie rodzi to problemu, o ile funkcja używająca nie zamierza przechowywać tego pointera, a tylko go używa w momencie wywołania.
//void Texture::render( const SDL_Rect r, const SDL_Rect clip, SDL_Renderer* gRenderer )

Uznałem, że pominę te błędy, pokasowałem je i wyłonił mi się jeszcze jeden błąd, którego nie rozumiem..


==9578== Mismatched free() / delete / delete []
==9578==    at 0x4C2F400: operator delete(void*) (vg_replace_malloc.c:576)
==9578==    by 0x407500: Object::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, SDL_Rect, SDL_Renderer*) (Object.cpp:53)
==9578==    by 0x4075E8: Object::draw(SDL_Renderer*) (Object.cpp:67)
==9578==    by 0x4092F6: Scene::draw_objects() (Scene.cpp:113)
==9578==    by 0x408F66: Scene::draw_scene() (Scene.cpp:34)
==9578==    by 0x403B6C: Game::loop() (Game.cpp:96)
==9578==    by 0x402D4E: main (main.cpp:14)
==9578==  Address 0x12c2cd50 is 0 bytes inside a block of size 96 alloc'd
==9578==    at 0x4C2FF6C: calloc (vg_replace_malloc.c:752)
==9578==    by 0x4EE737F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.4.0)
==9578==    by 0x537467E: TTF_RenderUTF8_Solid (in /usr/lib/x86_64-linux-gnu/libSDL2_ttf-2.0.so.0.14.0)
==9578==    by 0x5374A69: TTF_RenderText_Solid (in /usr/lib/x86_64-linux-gnu/libSDL2_ttf-2.0.so.0.14.0)
==9578==    by 0x407407: Object::write(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, SDL_Rect, SDL_Renderer*) (Object.cpp:38)
==9578==    by 0x4075E8: Object::draw(SDL_Renderer*) (Object.cpp:67)
==9578==    by 0x4092F6: Scene::draw_objects() (Scene.cpp:113)
==9578==    by 0x408F66: Scene::draw_scene() (Scene.cpp:34)
==9578==    by 0x403B6C: Game::loop() (Game.cpp:96)
==9578==    by 0x402D4E: main (main.cpp:14)
==9578==

Wrzucę kod, który wydaje mi się istotny. W razie czego podam go więcej oczywiście...
C/C++
/*l:32*/ void Object::write( std::string caption, SDL_Rect placement, SDL_Renderer * renderer )
/*l:33*/ {
    /*l:34*/ SDL_Color font_color = { 210, 210, 250 };
    /*l:35*/ SDL_Surface * text_surface;
    /*l:36*/ if( caption != "" )
    /*l:37*/ {
        /*l:38*/ if( !( text_surface = TTF_RenderText_Solid( font, caption.c_str(), font_color ) ) ) {
            /*l:39*/ std::cout << "E: Could not create surface from text : " << TTF_GetError << std::endl;
            /*l:40*/ }
        /*l:41*/ else {
            /*l:42*/ SDL_Texture * text_text = SDL_CreateTextureFromSurface( renderer, text_surface );
            /*l:43*/
            /*l:44*/ int text_x =( placement.x + placement.w / 2 ) - text_surface->w / 2;
            /*l:45*/ int text_y =( placement.y + placement.h / 2 ) - text_surface->h / 2;
            /*l:46*/ SDL_Rect renderQuad = { text_x, text_y, text_surface->w, text_surface->h };
            /*l:47*/
            /*l:48*/
            /*l:49*/ //Render to screen
            /*l:50*/ SDL_RenderCopy( renderer, text_text, NULL, & renderQuad );
            /*l:51*/
            /*l:52*/ SDL_DestroyTexture( text_text );
            /*l:53*/ delete text_surface; //mismatched delete <- czyżby znowu SDL robił coś dziwnego z moim wskaźnikiem w lini 38?/42?
            /*l:54*/ }
        /*l:55*/ }
    /*l:56*/ }

Niestety nigdy w życiu nie używałem valgrinda do tej pory i wydaje mi się że problem leży w SDL-u ( albo źle używam SDL_Renderer* (?) )

Przepraszam za chaotyczny post, ale próbuję -nie- napisać posta na 1000 linijek i przeskakuje wątkami w głowie tak, żeby szybko przekazać dużo treści.

Odcinając się trochę tematu stricte błedów postanowiłem użyć valgrinda, żeby wytropić wyciek pamięci, którego się dorobiłem pisząc swoją grę. Po odpaleniu mapy wycieka mi ~1%RAMu na 2-3 sekundy ( z 4GB RAM -> 10-20MB/s -> być może 330kb na każdą klatkę (60FPS) ). Najgorsze, że nie wiem kiedy wyciek powstał i w którym miejscu kodu go szukać, bo wykryłem go teraz, ale najprawdopodobniej jest on już jakiś czas (pierwszy raz testowałem grę przez ponad kilka minut i skończył mi się ram, zacząłem korzystać ze swapu i ... i tak dalej).

Myślę, że te 330kb/klatkę ładnie pasowałoby do kilku surface-ów stworzonych za pomocą TTF_RenderText_Solid, których np nie udaje mi się zdealokować.
Albo cały problem leży w tym że źle używam pointera do SDL_Renderer i o tym nie wiem.


Dorzucę więcej kodu kilku klas w razie gdyby ktoś był ciekawy

od razu dodam, że fonty potraktowałem mocno po macoszemu i są bardzo tym czasowo zastosowane. Nie mam jeszcze pomysłu jak je ładnie ułożyć/włożyć do jakiejś struktury

Object.cpp
C/C++
#include "Object.h"
#include "Texture.h"
#include "Scene.h"

TTF_Font * Object::font;

Object::Object( Scene * host )
{
    placement.x = 0;
    placement.y = 0;
    texture = nullptr;
    overlay = nullptr;
    host->addObject( this );
}

void Object::resetWH()
{
    placement.w = texture->getWidth();
    placement.h = texture->getHeight();
}

bool Object::cover( int x, int y )
{
    if( x > placement.x )
    if( x < placement.x + placement.w )
    if( y > placement.y )
    if( y < placement.y + placement.h )
         return true;
   
    return false;
}

void Object::write( std::string caption, SDL_Rect placement, SDL_Renderer * renderer )
{
    SDL_Color font_color = { 210, 210, 250 };
    SDL_Surface * text_surface;
    if( caption != "" )
    {
        if( !( text_surface = TTF_RenderText_Solid( font, caption.c_str(), font_color ) ) ) {
            std::cout << "E: Could not create surface from text : " << TTF_GetError << std::endl;
        }
        else {
            SDL_Texture * text_text = SDL_CreateTextureFromSurface( renderer, text_surface );
           
            int text_x =( placement.x + placement.w / 2 ) - text_surface->w / 2;
            int text_y =( placement.y + placement.h / 2 ) - text_surface->h / 2;
            SDL_Rect renderQuad = { text_x, text_y, text_surface->w, text_surface->h };
           
           
            //Render to screen
            SDL_RenderCopy( renderer, text_text, NULL, & renderQuad );
           
            SDL_DestroyTexture( text_text );
            delete text_surface;
        }
    }
}

void Object::draw( SDL_Renderer * renderer )
{
    if( texture != NULL )
         texture->render( placement, renderer );
    else
         std::cout << "E: Texture is null! Cannot display object" << std::endl;
   
    if( overlay != NULL )
         overlay->render( placement, renderer );
   
    write( caption, placement, renderer );
   
    //    SDL_Color font_color={0x7F,0x33,0x00};
   
}
Texture.cpp
C/C++
#include "Texture.h"

std::vector < texname *> Texture_bank::tex;


int SDL_SetRenderDrawColor( SDL_Renderer * target, SDL_Color c )
{
    return SDL_SetRenderDrawColor( target, c.r, c.g, c.b, c.a );
}

// poniżej takie tymczasowe, a moze i stałe rozwiązanie na to, że chciałem trochę bardziej arbitrarnie móc sobie zawołać konkretną teksturę, nie wiedząc nawet który obiekt ją trzyma i nawet jak wygląda obiekt, który ją przechowuje. Chyba niezbyt bezpieczne rozwiązanie, ale chciałem działać, a co chwila kombinowałem z układniem includów tak, żeby jedna klasa widziała tekstury drugiej... tak po prostu - wystarczy że znam nazwę. Chętnie usłyszę zdanie, czy to dobre rozwiązanie, ale nie jest to zupełnie związane z tematem.
unsigned int Texture_bank::add( Texture * t, std::string n )
{ ///returns ID of added texture
    if( Texture_bank::get_by_name( n ) != NULL )
         std::cout << "W: Texture name duplicate : " << n << std::endl;
   
    texname * texx = new texname();
    texx->ture = t;
    texx->name = n;
    tex.push_back( texx );
    return(( tex.size() - 1 ) );
   
}

Texture * Texture_bank::get_by_name( std::string name )
{ ///returns Texture after giving its name
    if( tex.size() > 0 )
    for( unsigned int i = 0; i < tex.size(); i++ )
    {
        if( tex[ i ]->name == name )
             return tex[ i ]->ture; // if not found
       
    }
    return NULL;
   
}

void Texture_bank::delete_all()
{
    for( texname * t: tex )
         t->ture->free();
   
    tex.clear();
}

std::vector < texname *> Texture_bank::get_all()
{
    return tex;
}

void Texture_bank::remove_by_pointer( Texture * texture )
{
    for( unsigned int i = 0; i < tex.size(); i++ )
    if( tex[ i ]->ture == texture )
    {
        tex[ i ]->ture->free();
        tex.erase( tex.begin() + i );
    }
}



std::string Texture::resources_path;

Texture::Texture( std::string name )
    : mTexture( NULL )
     , mWidth( 0 )
     , mHeight( 0 )
{
    Texture_bank::add( this, name );
}
Texture::Texture( std::string name, std::string new_path )
    : mTexture( NULL )
     , mWidth( 0 )
     , mHeight( 0 )
{
    Texture_bank::add( this, name );
    declare_path( new_path );
}
Texture::~Texture() {
    Texture_bank::remove_by_pointer( this );
    free();
}

void Texture::declare_path( std::string new_path )
{
    path = new_path;
    free();
}

bool Texture::reload( SDL_Renderer * gRenderer )
{
    //printf ("loading texture : %s%s\n", resources_path.c_str(), path.c_str());
   
    SDL_Texture * newTexture = NULL;
    // tutaj nie usuwam tych 2 struktur -> teraz to zauważyłem. Jestem jednak prawie pewien, że narazie używam ::reload tylko na początku działania programu. Nie mnie jednak, muszę się temu dokładniej przyjrzeć i dorzucić delete'y w razie potrzeby.
    SDL_Surface * loadedSurface = IMG_Load(( resources_path + path ).c_str() );
   
    if( loadedSurface == NULL )
    {
        printf( "Critical Error, Aborting! Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
        exit( 1 );
    }
    else
    {
        // makes transparent pixel at this* color                                          *this
        // SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );
       
        newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
       
        if( newTexture == NULL )
        {
            printf( "Critical Error, Aborting! Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
            exit( 1 );
        }
        else
        {
            mWidth = loadedSurface->w;
            mHeight = loadedSurface->h;
        }
       
        SDL_FreeSurface( loadedSurface );
    }
   
    mTexture = newTexture;
    return mTexture != NULL;
   
}
#include <sstream>
void Texture::LOAD_ALL_TEXTURES( SDL_Renderer * gRenderer )
{
    std::vector < texname *> tex_list;
   
    tex_list = Texture_bank::get_all();
   
    std::cout << " -- LOADING TEXTURES -- " << std::endl;
    for( unsigned int i = 0; i < tex_list.size(); i++ )
    {
        std::stringstream data;
        unsigned int actual =(( i ) * 100 ) / tex_list.size();
        data << "[ ";
        if( actual < 10 )
             data << " ";
       
        if( actual < 100 )
             data << " ";
       
        data << actual << "% ] " << i + 1 << " out of " << tex_list.size() << std::endl;
       
        std::cout << data.str();
        tex_list[ i ]->ture->reload( gRenderer );
    }
    if( tex_list.size() != 0 )
         std::cout << "[ " << 100 << "% ]" << std::endl;
   
    std::cout << " -- DONE * " << tex_list.size() << " * TEXTURES LOADED! -- " << std::endl;
   
   
}

void Texture::free()
{
    //Free texture if it exists
    if( mTexture != NULL )
    {
        SDL_DestroyTexture( mTexture );
        mTexture = NULL;
        mWidth = 0;
        mHeight = 0;
    }
   
}
void Texture::render( const SDL_Point p, const SDL_Rect clip, SDL_Renderer * gRenderer )
{
    SDL_Rect renderQuad = { p.x, p.y, mWidth, mHeight };
    render( renderQuad, clip, gRenderer );
   
}
void Texture::render( const SDL_Rect r, const SDL_Rect clip, SDL_Renderer * gRenderer )
{
    SDL_RenderCopy( gRenderer, mTexture, & clip, & r );
   
} void Texture::render( const SDL_Point p, SDL_Renderer * gRenderer )
{
    SDL_Rect renderQuad = { p.x, p.y, mWidth, mHeight };
    render( renderQuad, gRenderer );
    //alternate route
    //SDL_Rect clip = {0,0,mWidth,mHeight};
    //render (p, clip, gRenderer);
}
void Texture::render( const SDL_Rect r, SDL_Renderer * gRenderer )
{
    SDL_Rect clip = { 0, 0, mWidth, mHeight };
    render( r, clip, gRenderer );
}
int Texture::getWidth() { return mWidth; }
int Texture::getHeight() { return mHeight; }
void Texture::set_texture( SDL_Texture * tex, unsigned int w, unsigned int h )
{
    mTexture = tex;
    mWidth = w;
    mHeight = h;
}

SDL_Texture * Texture::get_texture() { return mTexture; }

void Texture::free_all()
{
    Texture_bank::delete_all();
}



/*#include <SDL2/SDL_ttf.h>
std::string Texture::resources_path;
#include <iostream>
Texture::Texture () : mTexture(NULL), mWidth(0), mHeight(0)
{
    textures.push_back(this);
}
!!! path load before renderer init ==> problems !!!
Texture::Texture ( std::string path, SDL_Renderer* gRenderer ): mTexture(NULL), mWidth(0), mHeight(0)
{
    textures.push_back(this);
    loadFromFile(path,gRenderer);
}
Texture::~Texture(){free();}
bool Texture::loadFromFile( std::string path, SDL_Renderer* gRenderer )
{
free();

    printf ("loading texture : %s%s\n", resources_path.c_str(), path.c_str());

SDL_Texture* newTexture = NULL;

SDL_Surface* loadedSurface = IMG_Load( ( resources_path+path ).c_str() );

if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else
{
    // makes transparent pixel at this* color                                          *this
// SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );

        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
{
mWidth = loadedSurface->w;
mHeight = loadedSurface->h;
}

SDL_FreeSurface( loadedSurface );
}

mTexture = newTexture;
return mTexture != NULL;
}
void Texture::free()
{
    //Free texture if it exists
    if( mTexture != NULL )
    {
        SDL_DestroyTexture( mTexture );
        mTexture = NULL;
        mWidth = 0;
        mHeight = 0;
    }
}

void Texture::render( SDL_Point* p, SDL_Rect* clip, SDL_Renderer* gRenderer )
{
    SDL_Rect renderQuad = { p->x, p->y, mWidth, mHeight };
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}

//Render to screen
SDL_RenderCopy( gRenderer, mTexture, clip, &renderQuad );

}
void Texture::render( SDL_Rect* r, SDL_Rect* clip, SDL_Renderer* gRenderer )
{
    SDL_Rect renderQuad = { r->x, r->y, r->w, r->h };
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}

//Render to screen
SDL_RenderCopy( gRenderer, mTexture, clip, &renderQuad );

}
int Texture::getWidth() {return mWidth;}
int Texture::getHeight() {return mHeight;}
void Texture::set_texture( SDL_Texture* tex, unsigned int w, unsigned int h)
{
    mTexture = tex;
    mWidth = w;
    mHeight = h;
}
SDL_Texture* Texture::get_texture(){return mTexture;}
void Texture::free_all()
{
    for (unsigned int i=0;i<textures.size();i++)
    {
        delete textures[i];
    }
    textures.clear();
}
std::vector <Texture*> Texture::textures;
*/
Game.cpp
C/C++
#include "Texture.h"

std::vector < texname *> Texture_bank::tex;


int SDL_SetRenderDrawColor( SDL_Renderer * target, SDL_Color c )
{
    return SDL_SetRenderDrawColor( target, c.r, c.g, c.b, c.a );
}


unsigned int Texture_bank::add( Texture * t, std::string n )
{ ///returns ID of added texture
    if( Texture_bank::get_by_name( n ) != NULL )
         std::cout << "W: Texture name duplicate : " << n << std::endl;
   
    texname * texx = new texname();
    texx->ture = t;
    texx->name = n;
    tex.push_back( texx );
    return(( tex.size() - 1 ) );
   
}

Texture * Texture_bank::get_by_name( std::string name )
{ ///returns Texture after giving its name
    if( tex.size() > 0 )
    for( unsigned int i = 0; i < tex.size(); i++ )
    {
        if( tex[ i ]->name == name )
             return tex[ i ]->ture; // if not found
       
    }
    return NULL;
   
}

void Texture_bank::delete_all()
{
    for( texname * t: tex )
         t->ture->free();
   
    tex.clear();
}

std::vector < texname *> Texture_bank::get_all()
{
    return tex;
}

void Texture_bank::remove_by_pointer( Texture * texture )
{
    for( unsigned int i = 0; i < tex.size(); i++ )
    if( tex[ i ]->ture == texture )
    {
        tex[ i ]->ture->free();
        tex.erase( tex.begin() + i );
    }
}



std::string Texture::resources_path;

Texture::Texture( std::string name )
    : mTexture( NULL )
     , mWidth( 0 )
     , mHeight( 0 )
{
    Texture_bank::add( this, name );
}
Texture::Texture( std::string name, std::string new_path )
    : mTexture( NULL )
     , mWidth( 0 )
     , mHeight( 0 )
{
    Texture_bank::add( this, name );
    declare_path( new_path );
}
Texture::~Texture() {
    Texture_bank::remove_by_pointer( this );
    free();
}

void Texture::declare_path( std::string new_path )
{
    path = new_path;
    free();
}

bool Texture::reload( SDL_Renderer * gRenderer )
{
    //printf ("loading texture : %s%s\n", resources_path.c_str(), path.c_str());
   
    SDL_Texture * newTexture = NULL;
   
    SDL_Surface * loadedSurface = IMG_Load(( resources_path + path ).c_str() );
   
    if( loadedSurface == NULL )
    {
        printf( "Critical Error, Aborting! Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
        exit( 1 );
    }
    else
    {
        // makes transparent pixel at this* color                                          *this
        // SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );
       
        newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
       
        if( newTexture == NULL )
        {
            printf( "Critical Error, Aborting! Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
            exit( 1 );
        }
        else
        {
            mWidth = loadedSurface->w;
            mHeight = loadedSurface->h;
        }
       
        SDL_FreeSurface( loadedSurface );
    }
   
    mTexture = newTexture;
    return mTexture != NULL;
   
}
#include <sstream>
void Texture::LOAD_ALL_TEXTURES( SDL_Renderer * gRenderer )
{
    std::vector < texname *> tex_list;
   
    tex_list = Texture_bank::get_all();
   
    std::cout << " -- LOADING TEXTURES -- " << std::endl;
    for( unsigned int i = 0; i < tex_list.size(); i++ )
    {
        std::stringstream data;
        unsigned int actual =(( i ) * 100 ) / tex_list.size();
        data << "[ ";
        if( actual < 10 )
             data << " ";
       
        if( actual < 100 )
             data << " ";
       
        data << actual << "% ] " << i + 1 << " out of " << tex_list.size() << std::endl;
       
        std::cout << data.str();
        tex_list[ i ]->ture->reload( gRenderer );
    }
    if( tex_list.size() != 0 )
         std::cout << "[ " << 100 << "% ]" << std::endl;
   
    std::cout << " -- DONE * " << tex_list.size() << " * TEXTURES LOADED! -- " << std::endl;
   
   
}

void Texture::free()
{
    //Free texture if it exists
    if( mTexture != NULL )
    {
        SDL_DestroyTexture( mTexture );
        mTexture = NULL;
        mWidth = 0;
        mHeight = 0;
    }
   
}
void Texture::render( const SDL_Point p, const SDL_Rect clip, SDL_Renderer * gRenderer )
{
    SDL_Rect renderQuad = { p.x, p.y, mWidth, mHeight };
    render( renderQuad, clip, gRenderer );
   
}
void Texture::render( const SDL_Rect r, const SDL_Rect clip, SDL_Renderer * gRenderer )
{
    SDL_RenderCopy( gRenderer, mTexture, & clip, & r );
   
} void Texture::render( const SDL_Point p, SDL_Renderer * gRenderer )
{
    SDL_Rect renderQuad = { p.x, p.y, mWidth, mHeight };
    render( renderQuad, gRenderer );
    //alternate route
    //SDL_Rect clip = {0,0,mWidth,mHeight};
    //render (p, clip, gRenderer);
}
void Texture::render( const SDL_Rect r, SDL_Renderer * gRenderer )
{
    SDL_Rect clip = { 0, 0, mWidth, mHeight };
    render( r, clip, gRenderer );
}
int Texture::getWidth() { return mWidth; }
int Texture::getHeight() { return mHeight; }
void Texture::set_texture( SDL_Texture * tex, unsigned int w, unsigned int h )
{
    mTexture = tex;
    mWidth = w;
    mHeight = h;
}

SDL_Texture * Texture::get_texture() { return mTexture; }

void Texture::free_all()
{
    Texture_bank::delete_all();
}



/*#include <SDL2/SDL_ttf.h>
std::string Texture::resources_path;
#include <iostream>
Texture::Texture () : mTexture(NULL), mWidth(0), mHeight(0)
{
    textures.push_back(this);
}
!!! path load before renderer init ==> problems !!!
Texture::Texture ( std::string path, SDL_Renderer* gRenderer ): mTexture(NULL), mWidth(0), mHeight(0)
{
    textures.push_back(this);
    loadFromFile(path,gRenderer);
}
Texture::~Texture(){free();}
bool Texture::loadFromFile( std::string path, SDL_Renderer* gRenderer )
{
free();

    printf ("loading texture : %s%s\n", resources_path.c_str(), path.c_str());

SDL_Texture* newTexture = NULL;

SDL_Surface* loadedSurface = IMG_Load( ( resources_path+path ).c_str() );

if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else
{
    // makes transparent pixel at this* color                                          *this
// SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0, 0xFF, 0xFF ) );

        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
{
mWidth = loadedSurface->w;
mHeight = loadedSurface->h;
}

SDL_FreeSurface( loadedSurface );
}

mTexture = newTexture;
return mTexture != NULL;
}
void Texture::free()
{
    //Free texture if it exists
    if( mTexture != NULL )
    {
        SDL_DestroyTexture( mTexture );
        mTexture = NULL;
        mWidth = 0;
        mHeight = 0;
    }
}

void Texture::render( SDL_Point* p, SDL_Rect* clip, SDL_Renderer* gRenderer )
{
    SDL_Rect renderQuad = { p->x, p->y, mWidth, mHeight };
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}

//Render to screen
SDL_RenderCopy( gRenderer, mTexture, clip, &renderQuad );

}
void Texture::render( SDL_Rect* r, SDL_Rect* clip, SDL_Renderer* gRenderer )
{
    SDL_Rect renderQuad = { r->x, r->y, r->w, r->h };
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = clip->w;
renderQuad.h = clip->h;
}

//Render to screen
SDL_RenderCopy( gRenderer, mTexture, clip, &renderQuad );

}
int Texture::getWidth() {return mWidth;}
int Texture::getHeight() {return mHeight;}
void Texture::set_texture( SDL_Texture* tex, unsigned int w, unsigned int h)
{
    mTexture = tex;
    mWidth = w;
    mHeight = h;
}
SDL_Texture* Texture::get_texture(){return mTexture;}
void Texture::free_all()
{
    for (unsigned int i=0;i<textures.size();i++)
    {
        delete textures[i];
    }
    textures.clear();
}
std::vector <Texture*> Texture::textures;
*/

A poniżej istny festiwal tymczasowych rozwiązań, które później planuję zastąpić jakimś wczytywaniem danych z plików.

map.cpp
C/C++
#include "Map.h"

#include "Tile.h"
#include "Texture.h"
#include "Player.h"
#include <cstdint>

class Scene;

// tiles are 32x32
#define TILESIZE 48


enum players
{
    PNULL,
    Porange,
    Ppurple,
    Pblue,
    Pred,
    P_MAX
};

SDL_Color Pcols[ P_MAX ];


Player * Pzero = new Player();
Player * P1 = new Player();
Player * P2 = new Player();
Player * P3 = new Player();
Player * P4 = new Player();


Map::Map( Scene * parent, unsigned int height, unsigned int width )
    : Button( parent )
{
   
    height = 11;
    width = 11;
    int table[ 121 ] =
    {
        0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0,
        0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0,
        0, 0, 4, 0, 0, 1, 1, 0, 4, 0, 0,
        0, 0, 0, 3, 1, 1, 3, 3, 0, 0, 0,
       
        2, 2, 1, 3, 3, 2, 3, 1, 0, 2, 2,
        2, 2, 1, 1, 3, 3, 3, 1, 1, 2, 2,
        2, 2, 0, 1, 3, 2, 3, 3, 1, 2, 2,
       
        0, 0, 0, 3, 3, 1, 1, 3, 0, 0, 0,
        0, 0, 4, 0, 1, 1, 0, 0, 4, 0, 0,
        0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0,
        0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0,
    };
   
    map_width = 11;
   
    SDL_Point localization;
   
    for( localization.y = 0; localization.y < height; localization.y++ )
    {
        for( localization.x = 0; localization.x < width; localization.x++ )
        {
            Tile * t;
            int type = table[( localization.y * map_width ) + localization.x ];
            if( type < 4 )
                 t = new Tile(( Tile::types ) type, localization );
           
            if( type == 4 )
            {
                t = new Tile( Tile::grassland, localization );
                t->build_city();
            }
           
            t->set_owner( Pzero );
            t->have_unit = false;
           
            unsigned int h = localization.y; // coz im lazy..
            unsigned int w = localization.x;
           
            if( w > 0 && w < 4 && h > 0 && h < 4 )
            {
                t->set_owner( P1 );
            }
            if( w > 0 && w < 4 && h > 6 && h < 10 )
            {
                t->set_owner( P2 );
            }
            if( w > 6 && w < 10 && h > 0 && h < 4 )
            {
                t->set_owner( P3 );
            }
            if( w > 6 && w < 10 && h > 6 && h < 10 )
            {
                t->set_owner( P4 );
            }
           
            teritories.push_back( t );
        }
    }
   
    Object * O_temp;
   
    O_temp = new Object( parent );
    O_temp->set_placement(( SDL_Rect ) {.x = 580,.y = 120,.w = 200,.h = 60 } );
    O_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    P1->money_print = O_temp;
    O_temp = new Object( parent );
    O_temp->set_placement(( SDL_Rect ) {.x = 580,.y = 220,.w = 200,.h = 60 } );
    O_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    P2->money_print = O_temp;
    O_temp = new Object( parent );
    O_temp->set_placement(( SDL_Rect ) {.x = 580,.y = 320,.w = 200,.h = 60 } );
    O_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    P3->money_print = O_temp;
    O_temp = new Object( parent );
    O_temp->set_placement(( SDL_Rect ) {.x = 580,.y = 420,.w = 200,.h = 60 } );
    O_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    P4->money_print = O_temp;
    class EoT_Button
        : public Button
    {
    public: EoT_Button( Scene * s, Map * o_map )
            : Button( s )
        {
            owner_map = o_map;
        }
    private: void onClick( const SDL_Event & event ) {
            owner_map->EoT();
        }
        Map * owner_map;
    };
    O_temp = new EoT_Button( parent, this );
    O_temp->set_placement(( SDL_Rect ) {.x = 580,.y = 520,.w = 200,.h = 60 } );
    O_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    O_temp->set_caption( "End of Turn" );
   
    P1->get_money( 10000 );
    P2->get_money( 100 );
    P3->get_money( 100 );
    P4->get_money( 100 );
   
   
    cam.x = - 10;
    cam.y = - 10;
}

#define CASH_PER_CITY_LVL 100

void Map::EoT()
{
    for( Tile * teritory: teritories )
    {
        teritory->unit_move = true;
        teritory->get_owner()->get_money( teritory->get_city_lvl() * CASH_PER_CITY_LVL );
        Tile::selected = nullptr;
    }
}

void Map::draw( SDL_Renderer * renderer )
{
    Object::draw( renderer );
   
    #define FRAME_LAST 24
   
    if( draw_frame_counter < FRAME_LAST )
         draw_frame_counter++;
    else
         draw_frame_counter = 0;
   
    const int FIRST_TILE_X = cam.x / TILESIZE - 1;
    const int LAST_TILE_X =( cam.x + placement.h ) / TILESIZE + 1;
   
    const int FIRST_TILE_Y = cam.y / TILESIZE - 1;
    const int LAST_TILE_Y =( cam.y + placement.w ) / TILESIZE + 1;
   
    for( int tile_y = FIRST_TILE_Y; tile_y < LAST_TILE_Y; tile_y++ )
    {
        for( int tile_x = FIRST_TILE_X; tile_x < LAST_TILE_X; tile_x++ )
        {
            Texture * tex;
           
            Tile * terr = get_territory( tile_y, tile_x );
           
            if( terr != NULL )
            switch( terr->get_type() )
            {
            case Tile::grassland:
                tex = Texture_bank::get_by_name( "m_grassland" );
                break;
            case Tile::ocean:
                tex = Texture_bank::get_by_name( "m_ocean" );
                break;
            case Tile::desert:
                tex = Texture_bank::get_by_name( "m_desert" );
                break;
            case Tile::hills:
                tex = Texture_bank::get_by_name( "m_hills" );
                break;
                default:
                tex = Texture_bank::get_by_name( "m_grassland" );
            }
            else
                 tex = Texture_bank::get_by_name( "m_ambient" );
           
           
            SDL_Rect rend_place;
           
            rend_place.w = TILESIZE;
            rend_place.h = TILESIZE;
            rend_place.x = tile_x * TILESIZE + placement.x - cam.x;
            rend_place.y = tile_y * TILESIZE + placement.y - cam.y;
           
            if( rend_place.x < placement.x )
            {
                rend_place.w -= placement.x - rend_place.x;
                rend_place.x = placement.x;
            }
            if( rend_place.y < placement.y )
            {
                rend_place.h -= placement.y - rend_place.y;
                rend_place.y = placement.y;
            }
            int
            max_x = placement.x + placement.w - TILESIZE,
            max_y = placement.y + placement.h - TILESIZE;
            if( rend_place.x > max_x )
            {
                rend_place.w -= rend_place.x - max_x;
                rend_place.x = max_x + TILESIZE - rend_place.w;
            }
            if( rend_place.y > max_y )
            {
                rend_place.h -= rend_place.y - max_y;
                rend_place.y = max_y + TILESIZE - rend_place.h;
            }
           
            //clip_resize ( tex , TILESIZE , &clip );  repair it...
           
            tex->render( rend_place, renderer );
           
           
            if( terr != NULL )
            {
               
                SDL_Color col = terr->get_owner()->get_color();
                col.a *= 0.25;
                SDL_SetRenderDrawColor( renderer, col );
                SDL_RenderFillRect( renderer, & rend_place );
                if( terr->get_city_lvl() )
                {
                    tex = Texture_bank::get_by_name( "m_city" );
                    if( terr == Tile::selected )
                    {
                        if( draw_frame_counter > FRAME_LAST / 4 )
                             tex->render( rend_place, renderer );
                       
                    }
                    else
                         tex->render( rend_place, renderer );
                   
                    if( terr->get_city_lvl() > 1 )
                    {
                        std::string a = std::to_string( terr->get_city_lvl() );
                        Object::write( a, rend_place, renderer );
                    }
                }
                SDL_RenderFillRect( renderer, & rend_place );
               
                if( terr->have_unit )
                {
                    tex = Texture_bank::get_by_name( "m_soldier" );
                    if( terr == Tile::selected && terr->unit_move )
                    {
                        if( draw_frame_counter > FRAME_LAST / 4 )
                             tex->render( rend_place, renderer );
                       
                    }
                    else
                         tex->render( rend_place, renderer );
                   
                }
                if( terr == Tile::selected )
                {
                    tex = Texture_bank::get_by_name( "m_selection" );
                    tex->render( rend_place, renderer );
                }
               
            }
        }
    }
}

Tile * Map::get_territory( unsigned int y, unsigned int x ) /// returns tile witch is under Y x X
{
    unsigned int tNR = y * map_width + x;
    if( x >= map_width )
         return NULL;
   
    if( tNR < teritories.size() )
         return teritories[ tNR ];
    else
         return NULL;
   
}
void Map::onClick( const SDL_Event & event )
{
   
}

bool Map::fight( Tile * attacker, Tile * defender )
{
    int power_attack = 6;
    int power_defend = 6;
    if( defender->get_type() == Tile::desert )
         power_defend -= 2;
   
    if( defender->get_type() == Tile::hills )
         power_defend += 3;
   
    power_defend += defender->get_city_lvl();
   
   
   
    int attack_roll = Game::get_random( power_attack ); // 0-6
    int defend_roll = Game::get_random( power_defend ); // 0-power
   
    if( attack_roll > 4 )
         defender->raze_city(); // -1 lvl
   
    if( attack_roll > defend_roll )
         return true;
    else
    {
        if( attack_roll == defend_roll )
             defender->have_unit = false;
       
        attacker->have_unit = false;
        return false;
    }
}

bool Map::try_move( Tile * start, Tile * finish )
{
    if( start == finish )
         return false;
   
    if( start == nullptr or finish == nullptr )
         return false;
   
    if( finish->get_type() == Tile::ocean )
         return false;
   
    if( start->have_unit == false )
         return false;
   
    if( start->unit_move == false )
         return false;
   
    if( abs( finish->get_x() - start->get_x() ) > 1 or abs( finish->get_y() - start->get_y() ) > 1 )
         return false;
   
   
   
    if( finish->have_unit )
    {
        if( finish->get_owner() == start->get_owner() )
        {
            return false;
        }
        else
             return fight( start, finish );
       
    }
    return true;
}

void Map::onMouseUp( const SDL_Event & event )
{
   
    SDL_Point select;
    unsigned int x = event.button.x;
    unsigned int y = event.button.y;
    select.x =( x - placement.x + cam.x ) / TILESIZE;
    select.y =( y - placement.y + cam.y ) / TILESIZE;
   
    Tile * new_selected = get_territory( select.y, select.x );
   
    if( event.button.button == SDL_BUTTON_LEFT )
    {
        if( Tile::selected != NULL )
        if( Tile::selected->get_owner() == P1 )
        {
            if( Tile::selected == new_selected )
            {
                if( Tile::selected->have_unit == true )
                {
                    ;
                }
                else
                {
                    if( P1->pay( Pzero, 1000 ) )
                         new_selected->have_unit = true;
                   
                    new_selected->unit_move = true;
                    new_selected = NULL;
                }
            }
            if( try_move( Tile::selected, new_selected ) )
            {
                Tile::selected->have_unit = false;
                new_selected->have_unit = true;
                new_selected->unit_move = false;
                new_selected->set_owner( P1 );
                new_selected = NULL;
            }
        }
        Tile::selected = new_selected;
    }
    if( event.button.button == SDL_BUTTON_RIGHT )
    {
        if( Tile::selected != NULL )
        if( Tile::selected->get_owner() == P1 )
        {
            if( Tile::selected == new_selected )
            {
                if( Tile::selected->get_city_lvl() > 0 )
                {
                    if( P1->pay( Pzero, 3000 +( 1000 * new_selected->get_city_lvl() ) ) )
                         new_selected->build_city();
                   
                    new_selected = NULL;
                }
                else
                {
                    if( P1->pay( Pzero, 3000 ) )
                         new_selected->build_city();
                   
                    new_selected = NULL;
                }
            }
        }
    }
   
   
}

Scene_loader.cpp
C/C++
#include "Scenes/Scene_loader.h"
#include "Scene.h"
#include "Texture.h"
#include "Game.h"
#include "Button.h"
#include "Map.h"


Scene * Scene_loader::Main_menu;
Scene * Scene_loader::New_Game_scene;
Scene * Scene_loader::Game_scene;
Scene * Scene_loader::Settings;

void Scene_loader::init_scenes()
{
    Object * O_temp;
    Button * B_temp;
   
   
    new Texture( "scene main - background", "main menu/main scene.png" );
    new Texture( "scene game - background", "main menu/game scene.png" );
    new Texture( "game - background", "main menu/game back.png" );
    new Texture( "button base", "main menu/menu button.png" );
    new Texture( "map canvas - empty", "main menu/canvas.png" );
   
    new Texture( "m_selection", "game/Select.png" );
    new Texture( "m_ambient", "game/Ambient.png" );
   
    new Texture( "m_grassland", "game/Grassland.jpg" );
    new Texture( "m_desert", "game/Desert.jpg" );
    new Texture( "m_ocean", "game/Ocean.jpg" );
    new Texture( "m_hills", "game/Hills.jpg" );
   
    new Texture( "m_city", "game/city.png" );
    new Texture( "m_soldier", "game/assian_soldier.png" );
   
   
    new Texture( "Ppurple mark", "game/Purple.png" );
    new Texture( "Porange mark", "game/Orange.png" );
    new Texture( "Pblue mark", "game/Blue.png" );
    new Texture( "Pred mark", "game/Red.png" );
    // next.... =? //new Texture ( "map grassland" , "/game/Grassland.jpg" );
   
   
   
    class GScene
        : public Scene
    {
       
    public:
        GScene()
        {
            GMap = new Map( this, 5, 6 );
            GMap->set_placement(( SDL_Rect ) {.x = 12,.y = 12,.w = 548,.h = 548 } );
            GMap->set_texture( Texture_bank::get_by_name( "map canvas - empty" ) );
        }
       
    private:
        void get_KEY()
        {
            const Uint8 * keyboardState = SDL_GetKeyboardState( NULL );
            #define CAMERA_SPEED 4
            if( keyboardState[ SDL_SCANCODE_DOWN ] )
                 GMap->camera_mv( CAMERA_SPEED, 0 );
           
            if( keyboardState[ SDL_SCANCODE_UP ] )
                 GMap->camera_mv( - CAMERA_SPEED, 0 );
           
            if( keyboardState[ SDL_SCANCODE_RIGHT ] )
                 GMap->camera_mv( 0, CAMERA_SPEED );
           
            if( keyboardState[ SDL_SCANCODE_LEFT ] )
                 GMap->camera_mv( 0, - CAMERA_SPEED );
           
            if( keyboardState[ SDL_SCANCODE_ESCAPE ] )
                 Scene::load( Main_menu );
            //            switch (KEY.sym)
            //            {
            //                case SDLK_ESCAPE:
            //                    Scene::load(Main_menu);
            //                break;
            //                case SDLK_DOWN :
            //                    GMap->camera_mv(5,0);
            //                break;
            //                case SDLK_UP :
            //                    GMap->camera_mv(-5,0);
            //                break;
            //                case SDLK_LEFT :
            //                    GMap->camera_mv(0,-5);
            //                break;
            //                case SDLK_RIGHT :
            //                    GMap->camera_mv(0,5);
            //                break;
            //            }
        }
        Map * GMap;
    };
   
    Main_menu = new Scene();
    New_Game_scene = new Scene();
    Game_scene = new GScene();
    Settings = new Scene();
   
   
   
    Main_menu->setBackground( Texture_bank::get_by_name( "scene main - background" ) );
    Game::scenes.push_back( Main_menu );
   
    class New_Game_Button
        : public Button
    {
    public: New_Game_Button( Scene * s )
            : Button( s )
        { }
    private: void onClick( const SDL_Event & event ) { Scene::load( New_Game_scene ); }
    };
    B_temp = new New_Game_Button( Main_menu );
    B_temp->set_placement(( SDL_Rect ) {.x = 140,.y = 60,.w = 500,.h = 80 } );
    B_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    B_temp->set_caption( "New Game" );
   
   
    class Quit_Button
        : public Button
    {
    public: Quit_Button( Scene * s )
            : Button( s )
        { }
    private: void onClick( const SDL_Event & event ) { Game::exit(); }
    };
    B_temp = new Quit_Button( Main_menu );
    B_temp->set_placement(( SDL_Rect ) {.x = 140,.y = 460,.w = 500,.h = 80 } );
    B_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    B_temp->set_caption( "Exit" );
   
   
    New_Game_scene->setBackground( Texture_bank::get_by_name( "scene game - background" ) );
    Game::scenes.push_back( New_Game_scene );
   
    class Start_Game_Button
        : public Button
    {
    public: Start_Game_Button( Scene * s )
            : Button( s )
        { }
    private: void onClick( const SDL_Event & event ) { Scene::load( Game_scene ); }
    };
    B_temp = new Start_Game_Button( New_Game_scene );
    B_temp->set_placement(( SDL_Rect ) {.x = 140,.y = 60,.w = 500,.h = 80 } );
    B_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    B_temp->set_caption( "WTF button" );
   
   
    class Load_Main_Menu
        : public Button
    {
    public: Load_Main_Menu( Scene * s )
            : Button( s )
        { }
    private: void onClick( const SDL_Event & event ) { Scene::load( Main_menu ); }
    };
    B_temp = new Load_Main_Menu( New_Game_scene );
    B_temp->set_placement(( SDL_Rect ) {.x = 140,.y = 460,.w = 500,.h = 80 } );
    B_temp->set_texture( Texture_bank::get_by_name( "button base" ) );
    B_temp->set_caption( "Back" );
   
    Game_scene->setBackground( Texture_bank::get_by_name( "game - background" ) );
    Game::scenes.push_back( Game_scene );
   
   
}
P-173739
pekfos
» 2019-01-28 16:46:07
Nie możesz użyć delete do zwolnienia pamięci zaalokowanej inaczej niż przez new. SDL ma swoje funkcje do zwalniania pamięci.
P-173740
rafallauterbach
Temat założony przez niniejszego użytkownika
» 2019-01-28 16:57:42
SDL_FreeSurface()
(!) Ok, sprawdzę, czy pozbyłem się wycieku.

(...)
I nie ma już wycieku. Dzięki za wychwycenie tego!
P-173741
« 1 »
  Strona 1 z 1