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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Jimmyee

Pages: [1]
1
Graphics / Storing sprites in a container for better performance
« on: June 06, 2017, 01:52:34 pm »
Will I have better performance if I store created sprites in a container instead of creating them everytime while rendering graphics?

2
Can anyone tell me why is that? When I hold any key longer than 1 sec FPS of my game goes down from 32-35 to 1-5. I guess the game is flooded by input events and it doesn't process rendering so fast.
So my questions are:
is it common?
do I have to implement multithreading to avoid that?

3
EDIT: solved, look at the bottom of this post and thank you  :)

Hi. The challenge I have is to master the map rendering and I need help with solving this

I mean these tiles that are drawn right to the player. These additional tiles are drawn after every tile as you can see in this example where map size is 1x35. I have no clue what can cause it.

Here's the code I use to draw tiles:

/** gfxhandler.cpp */

shared_ptr<sf::Texture> GFXHandler::LoadTexture(std::string filename)
{
    map<std::string, shared_ptr<sf::Texture> >::iterator it;

    for(auto const &ent1 : textures)
    {
        if(ent1.first == filename)
        {
            return textures[filename];
        }
    }

    sf::Texture texture;
    if(!texture.loadFromFile(filename))
    {
        printf("GFXHandler: can't load texture %s\n", filename.c_str());
        return shared_ptr<sf::Texture>(0);
    }

    printf("GFXHandler: loaded %s\n", filename.c_str());
    textures[filename] = shared_ptr<sf::Texture>(new sf::Texture(texture));

    return textures[filename];
}

void GFXHandler::UnloadTexture(std::string filename)
{
    if(this->textures[filename].get())
    {
        this->textures[filename].reset();
    }
}

sf::Sprite GFXHandler::GetSprite(shared_ptr<sf::Texture> texture, unsigned int id)
{
    sf::Vector2u tsize = texture->getSize();
    sf::Sprite sprite;
    sprite.setTexture(*texture.get());

    int rectx = 0;
    int recty = 0;

    unsigned int yrows = (id * 32) / tsize.x;
    rectx = (id * 32) % tsize.x;
    recty = yrows * 32;

    sprite.setTextureRect(sf::IntRect(rectx, recty, rectx + 32, recty + 32));

    return sprite;
}

/** gfxhandler.hpp */

class GFXHandler
{
private:
map<std::string, shared_ptr<sf::Texture> > textures;

public:
shared_ptr<sf::Texture> LoadTexture(std::string filename);
void UnloadTexture(std::string filename);
sf::Sprite GetSprite(shared_ptr<sf::Texture> texture, unsigned int id);
};

/** map.cpp */
Map::Map(string filename, shared_ptr<GFXHandler> gfxhandler)
: datafile(filename)
{
    this->gfxhandler = gfxhandler;
    this->width = datafile.GetNumber();
    this->height = datafile.GetNumber();

    shared_ptr<sf::Texture> tex = this->gfxhandler->LoadTexture("gfx/map/1.png");

    this->layers[0].xrows.resize(this->width);

    for(int i = 0; i < this->width; ++i)
    {
    this->layers[0].xrows[i].yrow.tiles.resize(this->height);
        for(int ii = 0; ii < this->height; ++ii)
        {
            int id = datafile.GetNumber();
            this->layers[0].xrows[i].yrow.tiles[ii] = shared_ptr<Tile>(new Tile(id));
            shared_ptr<Tile> tile = this->layers[0].xrows[i].yrow.tiles[ii];
            if(tile->id != 0)
            {
                tile->sprite = gfxhandler->GetSprite(tex, tile->id - 1);
                tile->sprite.setPosition(sf::Vector2f(i * 32, ii * 32));
            }
            else
            {
                puts("Map: empty tile detected\n");
            }
        }
    }

    printf("Map created, %ix%i\n", this->width, this->height);
}

void Map::Draw(sf::RenderWindow *window, int x, int y)
{
    for(int i = 0; i < this->width; ++i)
    {
        for(int ii = 0; ii < this->height; ++ii)
        {
            shared_ptr<Tile> tile = this->layers[0].xrows[i].yrow.tiles[ii];
            int tile_x = i * 32 + x;
            int tile_y = ii * 32 + y;
            tile->sprite.setPosition(sf::Vector2f(tile_x, tile_y));
            window->draw(tile->sprite);
        }
    }
}

/** map.hpp */

class Map
{
public:
struct Tile
{
    unsigned int id;

    sf::Sprite sprite;

    Tile()
    : id(0)
    {
    }

    Tile(unsigned int id_)
    : id(id_)
    {

    }
};

struct Layer
{
    struct XRow
    {
        struct YRow
        {
            vector<shared_ptr<Tile>> tiles;
        } yrow;
    };

    vector<XRow> xrows;
};

private:
    DataFile datafile;
    int width;
    int height;
    Layer layers[1];

    shared_ptr<GFXHandler> gfxhandler;

public:
    Map(string filename, shared_ptr<GFXHandler> gfxhandler);
    void Draw(sf::RenderWindow *window, int x, int y);
    int Width() { return width; }
    int Height() { return height; }
};

 

Any help really appreciated...

EDIT!!!

 I've found the answer, this is not really anything serious...

In GFXHandler::GetSprite() function:
sprite.setTextureRect(sf::IntRect(rectx, recty, 32, 32));
// instead of sprite.setTextureRect(sf::IntRect(rectx, recty, rectx + 32, recty + 32));
 

Sorry for bothering anyone and it would be nice if someone delete this thread... ;)

4
Graphics / Too big textures...
« on: August 06, 2013, 08:03:24 pm »
I've got a problem while rendering a 2D map which is drawn using vertex arrays; first let me explain my idea:
I want to draw objects on the map. They have irregular size and are stored in separate graphic files. I need to load them by ID (ID is loaded from a map file).
I also want to have them all in one texture, so I will call the draw function only once.
Until now, my game was creating a virtual image and putting them all in it. It was also storing an information about each object size and possition on the "big texture".
The problem is that when I added more objects there were too many of them and the texture was too big (it gives me SFML error).
My question is: is there any other way to manage graphics like that? I don't want to call draw() too often :S

The only idea that comes to my mind is to create just another texture and put the rest of the objects there. Here's a code I wrote a while ago. It doesn't work but I hope it will show you what I mean...
void SpriteSheet::mergeImages(GFXLoader::Directory &dir)
{
    sf::Vector2f totalTextureSize;
    sf::Vector2f currentPossition;

    for(auto &img: dir.img)
    {
        unsigned int w = img.second.getSize().x;
        unsigned int h = img.second.getSize().y;

        if(currentPossition.x + w < sf::Texture::getMaximumSize())
        {
            currentPossition.x += w;
            if(totalTextureSize.x < currentPossition.x) totalTextureSize.x = currentPossition.x;
        }
        else
        {
            currentPossition.x = 0;
            currentPossition.y += h;
            if(totalTextureSize.y < currentPossition.y) totalTextureSize.y = currentPossition.y;
        }

        if(totalTextureSize.y < h) totalTextureSize.y = h;
    }

    unsigned int img_w = totalTextureSize.x > sf::Texture::getMaximumSize()?
                sf::Texture::getMaximumSize() : totalTextureSize.x;
    unsigned int img_h = totalTextureSize.y > sf::Texture::getMaximumSize()?
                sf::Texture::getMaximumSize() : totalTextureSize.y;

    sf::Image bigImage;
    bigImage.create(img_w, img_h, sf::Color(0, 0, 0));

    unsigned int textureCount = 0;
    unsigned int maxHeight = 0;
    unsigned int sprId = 0;
    sf::Vector2f remaining;
    remaining.x = totalTextureSize.x;
    remaining.y = totalTextureSize.y;
    currentPossition.x = 0;
    currentPossition.y = 0;
    for(auto &img: dir.img)
    {
        unsigned int w = img.second.getSize().x;
        unsigned int h = img.second.getSize().y;
        SpriteInfo sprInfo;
        sprInfo.textureId = textureCount;

        if(h > maxHeight) maxHeight = h;

        if(currentPossition.x + w < sf::Texture::getMaximumSize())
        {
            bigImage.copy(img.second, currentPossition.x, currentPossition.x, sf::IntRect(0, 0, w, h));
            sprInfo.rect = sf::IntRect(currentPossition.x, currentPossition.x, w, h);
            sprites[sprId] = sprInfo;
            currentPossition.x += w;
            sprId++;
        }
        else if(currentPossition.y + h < sf::Texture::getMaximumSize())
        {
            currentPossition.x = 0;
            currentPossition.y += maxHeight;
            remaining.y -= maxHeight;
            bigImage.copy(img.second, currentPossition.x, currentPossition.y, sf::IntRect(0, 0, w, h));
            sprInfo.rect = sf::IntRect(currentPossition.x, currentPossition.y, w, h);
            sprites[sprId] = sprInfo;
            sprId++;
        }
        else
        {
            images.push_back(bigImage);
            sf::Texture tex;
            tex.loadFromImage(images[images.size() - 1]);
            textures.push_back(tex);
            currentPossition.x = 0;
            currentPossition.y = 0;
            if(remaining.y > 0)
            {
                img_w = totalTextureSize.x > sf::Texture::getMaximumSize()?
                        sf::Texture::getMaximumSize() : totalTextureSize.x;
                img_h = remaining.y > sf::Texture::getMaximumSize()?
                        sf::Texture::getMaximumSize() : remaining.y;
                bigImage.create(img_w, img_h, sf::Color(0, 0, 0));
                textureCount++;
            }
        }
    }
}
 

5
Graphics / Is it good way to render a map?
« on: May 10, 2013, 05:53:22 pm »
Hello again. I've got a question about 2D map rendering. I am rendering a map using verticles and single texture with tiles. This is how the code looks like:

MapRender::Tile::Tile(MapRender &map_render_, std::shared_ptr<MapFile::Tile> file_data_)
: map_render(map_render_)
, file_data(file_data_)
{
    verticles.setPrimitiveType(sf::Quads);
    verticles.resize(4);
    update_verticles();
}

void MapRender::Tile::update_verticles()
{
    sf::Vertex *quad = &verticles[0];
    int char_x = map_render.game.me->x * 32;
    int char_y = map_render.game.me->y * 32;
    int x1 = (file_data->x * 32) - char_x;
    int y1 = (file_data->y * 32) - char_y;
    int x2 = ((file_data->x * 32) - char_x) + 32;
    int y2 = ((file_data->y * 32) - char_y) + 32;


    quad[0].position = sf::Vector2f(x1, y1);
    quad[1].position = sf::Vector2f(x2, y1);
    quad[2].position = sf::Vector2f(x2, y2);
    quad[3].position = sf::Vector2f(x1, y2);

    sf::FloatRect rect = file_data->sprite_rect;
    quad[0].texCoords = sf::Vector2f(rect.left, rect.top);
    quad[1].texCoords = sf::Vector2f(rect.left + rect.width, rect.top);
    quad[2].texCoords = sf::Vector2f(rect.left + rect.width, rect.top + rect.height);
    quad[3].texCoords = sf::Vector2f(rect.left, rect.top + rect.height);
}

MapRender::MapRender(MapFile &map_file_, Game &game_)
: map_file(map_file_)
, game(game_)
{
    construct();
}

// it's called in the main loop with sf::RenderWindow
void MapRender::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
    states.texture = &game.gfx_loader->dir["map/"].tex[map_file.texture_id];
    target.draw(tile_verticles, states);
}

void MapRender::process()
{
    update_verticles();
}

void MapRender::update_verticles()
{
    for(int y = 0; y < map_file.height; ++y)
    {
        for(int x = 0; x < map_file.width; ++x)
        {
            tiles[0][x][y]->update_verticles();
            for(int i = 0; i < 4; ++i)
                tile_verticles[(1 * ((((4 * x) + i) + ((y * map_file.width) * 4))))] = tiles[0][x][y]->verticles[i];
        }
    }
}

void MapRender::construct()
{
    tile_verticles.setPrimitiveType(sf::Quads);
    // 1 = amount of layers, 4 = verticles per tile
    tile_verticles.resize(1 * ((map_file.width * map_file.height) * 4));

    for(int y = 0; y < map_file.height; ++y)
    {
        for(int x = 0; x < map_file.width; ++x)
        {
            tiles[0][x][y] = std::shared_ptr<Tile>(new Tile(*this, map_file.tiles[0][x][y]));
            tiles[0][x][y]->update_verticles();
            for(int i = 0; i < 4; ++i)
                tile_verticles[(1 * ((((4 * x) + i) + ((y * map_file.width) * 4))))] = tiles[0][x][y]->verticles[i];
        }
    }
}

There is a simple character too, the map possition is based on it's coordinates. Everytime I press any arrow key, I set the new character possition and call MapRender::process() to update all the verticles to new possitions. Is there a better way to move the map without updating 10000's of verticles? :D I guess it can be done with sf::View but I have no idea how to use it... I have read the tutorial already but there are problems still. Can you give me some hint?

6
Graphics / How to merge textures quickly?
« on: May 09, 2013, 09:30:57 pm »
How to do that quickly? D I have to use RenderTexture? I have to create a big texture so I can use only one while drawing 2D map with vertex arrays. I thought it's possible through sf::Image somehow but I can't get it working.

7
Hello. I've been trying to render a map without lose of CPU. Some day I found this: http://www.sfml-dev.org/tutorials/2.0/graphics-vertex-array.php It's a good tutorial but it didn't help me at all and there is my question: how can I render a map using vertex arrays with use of multiple textures loaded from files? My map tiles are saved in several files and I don't want to call draw() so often but only once. Should I join all the textures to a big one (if it's possible) and use it?

Pages: [1]