Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: C++ white boxes displaying  (Read 3501 times)

0 Members and 1 Guest are viewing this topic.

corpseRott

  • Newbie
  • *
  • Posts: 2
    • View Profile
C++ white boxes displaying
« on: April 02, 2014, 10:45:32 pm »
Hey, hope you guys can help. I've recently started rewriting my SDL driven RTS game to SFML (due to various reasons). I am trying to write a class to draw out the map from a tileset, but its just displaying a bunch of white squares on the screen. Now, I have read before that this might be due to the texture being destroyed while sprites are still using it (a case of declaring the texture locally), but it appears that my texture is still there safe and sound. To avoid loading textures constantly I am keeping my sprites in a vector, don't know if that matters.

Here is the code in question:

C++
void TerrainMap::drawMap()
{
    unsigned int i;
    unsigned int j;
    sf::Sprite tmp;

    for(j = 0; j < (this->sizeY); j++)
    {
        for(i = 0; i < (this->sizeX); i++)
        {
            tmp = mDatabase.getSpriteId(mapArray[i][j]); /* Fetching Sprite from Database*/
            tmp.setPosition(sf::Vector2f(i*90,j*90)); /* Dislocating Sprite */
            this->mWindow.draw(tmp);
            std::cout << "Placing Sprite" << std::endl;
        }
    }
}

sf::Sprite SpriteDatabase::getSpriteId(unsigned int id) const
{
    std::cout << "Returning Sprite\n" << std::endl;
    return spriteIndex[id];
}

void SpriteDatabase::loadSprite(sf::Sprite sprite) /* Push into vector container */
{
    std::cout << "Loading Sprite\n" << std::endl;
    spriteIndex.push_back(sprite);
}

bool SpriteDatabase::preloadDatabase()
{
    sf::Sprite sprite;

    if(!spriteIndex.empty())
        return false; /* If sprites have already been loaded */

    if(!texture.loadFromFile("gfxPack.png"))
        return false; /* If texture failed to load */

    sprite.setTexture(texture);

    sprite.setTextureRect(sf::IntRect(0,0,89,90));    /* Lime Grass */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(90,0,179,90));  /* Rough Sand */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(180,0,269,90)); /* Pure Sand */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(270,0,359,90)); /* Shallow Water */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(360,0,449,90)); /* Dirt */
    loadSprite(sprite);

    return true;
}

int main()
{
    SpriteDatabase sprDB;
    sf::RenderWindow window(sf::VideoMode(800,600), "Window");
    TerrainMap x(window, sprDB);
    x.setSize(12,12);
    x.loadMap("example.map");
    window.setVerticalSyncEnabled(true);

    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }
       
        window.clear(sf::Color::Black);
        x.drawMap();
        window.display();
    }
    return 0;
}

Headers:
#include <iostream>
#include <vector>
#include <SFML/Graphics.hpp>

/* Sprite Database -------------------------------- */
/* : Each Sprite has a unique id. ----------------- */
/* : use getSpriteId to return the sprite object -- */
/* ------------------------------------------------ */
/* LIST OF OBJECTS -------------------------------- */
/* 0. TERRAIN TEXTURE - Lime Grass ---------------- */
/* 1. TERRAIN TEXTURE - Rough Sand ---------------- */
/* 2. TERRAIN TEXTURE - Pure Sand ----------------- */
/* 3. TERRAIN TEXTURE - Shallow Water ------------- */
/* 4. TERRAIN TEXTURE - Dirt ---------------------- */
/* ------------------------------------------------ */
/* ------------------------------------------------ */

class SpriteDatabase
{
public:
    SpriteDatabase();
    sf::Sprite getSpriteId(unsigned int id) const;
private:
    void loadSprite(sf::Sprite sprite);
    bool preloadDatabase();
    std::vector<sf::Sprite> spriteIndex;
    sf::Texture texture;
};
 

class TerrainMap
{
public:
    TerrainMap(sf::RenderWindow& window, const SpriteDatabase& database) : mWindow(window), mDatabase(database) {};
    void setSize(unsigned int x, unsigned int y);
    void loadMap(const char* file);
    void drawMap();
private:
    sf::RenderWindow& mWindow;
    const SpriteDatabase& mDatabase;
    unsigned int mapArray[64][64];
    unsigned int sizeX;
    unsigned int sizeY;
};

coderx0x

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: C++ white boxes displaying
« Reply #1 on: April 02, 2014, 11:23:54 pm »
#include <iostream>
#include <vector>
#include <SFML/Graphics.hpp>

class SpriteDatabase
{
public:
    SpriteDatabase();
    ~SpriteDatabase();
    sf::Sprite & getSpriteId(unsigned int id);
private:
    void loadSprite(sf::Sprite *sprite);
    bool preloadDatabase();
    std::vector<sf::Sprite*> spriteIndex;
    sf::Texture texture;
};

sf::Sprite & SpriteDatabase::getSpriteId(unsigned int id)
{
    std::cout << "Returning Sprite\n" << std::endl;
    return (*spriteIndex[id]);
}

void SpriteDatabase::loadSprite(sf::Sprite *sprite) /* Push into vector container */
{
    std::cout << "Loading Sprite\n" << std::endl;
    spriteIndex.push_back(sprite);
}

bool SpriteDatabase::preloadDatabase()
{
    sf::Sprite *sprite;

    if(!spriteIndex.empty())
        return false;

    if(!texture.loadFromFile("gfxPack.png"))
        return false;

    sprite = new sf::Sprite(texture, sf::IntRect(0,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(90,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(180,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(270,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(360,0,89,90));
    loadSprite(sprite);

    return true;
}

SpriteDatabase::~SpriteDatabase()
{
    for (int = 0; i < spriteIndex.size(); i++)
    {
        delete spriteIndex[i];
    }
    spriteIndex.clear();
}

it work?


ADD:

Oh, Fuck...
You use sprite.setTextureRect(sf::IntRect(360,0,449,90));

1 parametr start texture rect x
2 parametr start texture rect y
3 parametr width texture rect
4 parametr height texture rect

    sprite.setTextureRect(sf::IntRect(0,0,89,90));    /* Lime Grass */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(90,0,89,90));  /* Rough Sand */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(180,0,89,90)); /* Pure Sand */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(270,0,89,90)); /* Shallow Water */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(360,0,89,90)); /* Dirt */
    loadSprite(sprite);
« Last Edit: April 03, 2014, 02:18:05 am by coderx0x »

math1992

  • Jr. Member
  • **
  • Posts: 77
    • View Profile
    • Email
Re: C++ white boxes displaying
« Reply #2 on: April 03, 2014, 12:31:27 am »
Why don't you simply use sf::VertexArray? Using sprite vector is not bad, but it requires to call a lot of draw in a short time. Also as explained in the tutorial, eventually you will reach your graphic card limit by using a lot of sprite.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: C++ white boxes displaying
« Reply #3 on: April 03, 2014, 09:18:58 am »
In general, you should always come up with a minimal and complete example that reproduces the problem. Read the link carefully, doing so will help you get better and faster answers.

By the way, your code is wrong (you don't adhere to the Rule Of Three) and unnecessarily error-prone (you don't use RAII).
« Last Edit: April 03, 2014, 09:22:01 am by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Nerevar

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • XGM
Re: C++ white boxes displaying
« Reply #4 on: April 03, 2014, 12:51:23 pm »
http://sfml-dev.org/tutorials/2.1/graphics-sprite.php
maybe?
>>The white square problem

coderx0x,hello from xgm :D

corpseRott

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: C++ white boxes displaying
« Reply #5 on: April 03, 2014, 08:00:04 pm »
#include <iostream>
#include <vector>
#include <SFML/Graphics.hpp>

class SpriteDatabase
{
public:
    SpriteDatabase();
    ~SpriteDatabase();
    sf::Sprite & getSpriteId(unsigned int id);
private:
    void loadSprite(sf::Sprite *sprite);
    bool preloadDatabase();
    std::vector<sf::Sprite*> spriteIndex;
    sf::Texture texture;
};

sf::Sprite & SpriteDatabase::getSpriteId(unsigned int id)
{
    std::cout << "Returning Sprite\n" << std::endl;
    return (*spriteIndex[id]);
}

void SpriteDatabase::loadSprite(sf::Sprite *sprite) /* Push into vector container */
{
    std::cout << "Loading Sprite\n" << std::endl;
    spriteIndex.push_back(sprite);
}

bool SpriteDatabase::preloadDatabase()
{
    sf::Sprite *sprite;

    if(!spriteIndex.empty())
        return false;

    if(!texture.loadFromFile("gfxPack.png"))
        return false;

    sprite = new sf::Sprite(texture, sf::IntRect(0,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(90,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(180,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(270,0,89,90));
    loadSprite(sprite);
    sprite = new sf::Sprite(texture, sf::IntRect(360,0,89,90));
    loadSprite(sprite);

    return true;
}

SpriteDatabase::~SpriteDatabase()
{
    for (int = 0; i < spriteIndex.size(); i++)
    {
        delete spriteIndex[i];
    }
    spriteIndex.clear();
}

it work?


ADD:

Oh, Fuck...
You use sprite.setTextureRect(sf::IntRect(360,0,449,90));

1 parametr start texture rect x
2 parametr start texture rect y
3 parametr width texture rect
4 parametr height texture rect

    sprite.setTextureRect(sf::IntRect(0,0,89,90));    /* Lime Grass */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(90,0,89,90));  /* Rough Sand */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(180,0,89,90)); /* Pure Sand */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(270,0,89,90)); /* Shallow Water */
    loadSprite(sprite);
    sprite.setTextureRect(sf::IntRect(360,0,89,90)); /* Dirt */
    loadSprite(sprite);

Thanks!
Works like a charm!

Regarding the setTextureRect, I am just used to SDL, and in SDL you explicitly give the x1,y1, x2,y2 coordinates of a rect rather than using a vector to later displace the sprite. Thats why I got it like that :p

I thought it actually returns a copy of a sprite rather than a reference. I figure i just didnt have the sprites properly allocated. Anyhow, a man learns his entire life, thanks :)

Quote from: Nexus
In general, you should always come up with a minimal and complete example that reproduces the problem. Read the link carefully, doing so will help you get better and faster answers.

By the way, your code is wrong (you don't adhere to the Rule Of Three) and unnecessarily error-prone (you don't use RAII).

No problem, I usually do that last, same with exception handling, I like to have everything working OK first before implementing memory management and operator overloading, same with exception handling (i usually just place a std::cout where an exception is most likely to appear at the end). I found this works perfect for me since I can just afterwards ran it over with a valgrind to patch everything up and optimize the code.

No worry I am not the type of a person which commits broken code to Git :)
Thanks for your feedback though, much appreciated :)

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: C++ white boxes displaying
« Reply #6 on: April 03, 2014, 08:48:55 pm »
Quote from: corpseRott
I like to have everything working OK first before implementing memory management and operator overloading
I hear this reasoning a lot, but it doesn't make sense. That's why included it in the myths section of my article ;)
Quote from: RAII Myth #5
There is no rational criterion determining a point in complexity, until which it is reasonable to abandon RAII -- especially considering the fact that the code may expand in the future. Since RAII requires no additional effort (the exact opposite is true), there is no reason not to use it from the beginning.

If you had avoided new/delete and used a std::vector<sf::Sprite> from the beginning, all your problems would have been gone: SpriteDatabase has correct copy semantics and it automatically cleans up. Since you don't have to write a destructor, code is both simpler and shorter.

Quote from: corpseRott
I found this works perfect for me since I can just afterwards ran it over with a valgrind to patch everything up and optimize the code.
When you use RAII consequently, there will be no more memory leaks, making it unnecessary to waste time with valgrind. You can actually save a lot of time by using modern C++ techniques. RAII is not an optimization, it's a fundamental idiom; it should never be given an afterthought.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: C++ white boxes displaying
« Reply #7 on: April 03, 2014, 08:49:46 pm »
Nexus: hear, hear!
You are right on the money.
Writing messy code may initially be faster but it always takes more time in the long run than just doing it properly in the first place.