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

Author Topic: Line artifacts when drawing tilemap  (Read 17624 times)

0 Members and 2 Guests are viewing this topic.

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #15 on: August 09, 2014, 07:31:44 pm »
Sorry for the bump, but I'm still having the issue. I've tried so many things, does no one really have any ideas what might be causing this?

Thanks

Jesper Juhl

  • Hero Member
  • *****
  • Posts: 1405
    • View Profile
    • Email
Re: Line artifacts when drawing tilemap
« Reply #16 on: August 09, 2014, 08:30:02 pm »
Have you tried the latest master from github? It has many bug fixes compared to 2.1 (which I'm assuming you are using).

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #17 on: August 10, 2014, 01:39:26 pm »
I fixed similiar problem by using 1 pixel margin around tiles in spritesheet. For some reason GPU was pulling pixels from outside of the texcoords.

I tried this, but it made the problem even more apparent with even larger black lines.

I forgot to add that this margin should have same colors as the tile. So if you need 40x40 tiles, you need to draw 42x42 tiles and use rectangle 1 pixels from the edges. If that won't work, you should just post working example of the problem.
SFML.Utils - useful extensions for SFML.Net

BaneTrapper

  • Full Member
  • ***
  • Posts: 213
  • Do you even see this, i dont need it.
    • View Profile
    • Email
Re: Line artifacts when drawing tilemap
« Reply #18 on: August 10, 2014, 06:00:52 pm »
Ok, here's the entirety of all of my relevant code:

Player.hpp

class Player : public Entity
        {
        public:
                typedef std::shared_ptr<Player> Ptr;

                static Ptr create(const std::string& id = "player") { Ptr temp(new Player(id)); return temp; }

                void handleCollision();

                void move(const sf::Vector2f& offset);

                virtual void update(sf::Time dt);

                void draw(sf::RenderTarget& target, sf::RenderStates states) const;

        private:
                Player(const std::string& id = "player", bool active = true);

                sf::Texture m_texture;
                sf::Sprite m_sprite;

                sf::Vector2f m_viewArea;

                bool nextPosValid(const sf::Vector2f& offset);
                bool rectOverlapsTile(const sf::FloatRect& rect);
        };

Player.cpp

        Player::Player(const std::string& id, bool active) :
                m_viewArea(sf::Vector2f(100, 100))
        {
                m_texture.loadFromFile("Resources/player.png");
                m_sprite.setTexture(m_texture);
                m_sprite.setPosition(350, 300);

                registerAttribute("renderable", new bool(true));
                registerAttribute("health", new int(20));

                SceneManager::getView().setCenter(std::floor(350), std::floor(300));
                SceneManager::getView().setSize(m_viewArea);
        }

        bool Player::nextPosValid(const sf::Vector2f& offset)
        {
                sf::Vector2f offsettedPos(std::floor(m_sprite.getPosition().x + offset.x), std::floor(m_sprite.getPosition().y + offset.y));

                //The bounding rectangle of the future player
                sf::FloatRect rect(offsettedPos, sf::Vector2f(std::floor(m_sprite.getGlobalBounds().width), std::floor(m_sprite.getGlobalBounds().height)));

                if (SceneManager::getWorld().getCurrentCell()->getTileMap().collidesWithType(2, rect))
                        return false;

                return true;
        }

        void Player::move(const sf::Vector2f& offset)
        {
                m_sprite.move(offset);
                SceneManager::getView().move(offset);
        }

        void Player::update(sf::Time dt)
        {
                if (InputManager::isActive(User_Input::UPHOLD))
                {
                        if (nextPosValid(sf::Vector2f(0, -100 * dt.asSeconds())))
                                move(sf::Vector2f(0, -100 * dt.asSeconds()));
                }

                if (InputManager::isActive(User_Input::LEFTHOLD))
                {
                        if (nextPosValid(sf::Vector2f(-100 * dt.asSeconds(), 0)))
                                move(sf::Vector2f(-100 * dt.asSeconds(), 0));
                }

                if (InputManager::isActive(User_Input::DOWNHOLD))
                {
                        if (nextPosValid(sf::Vector2f(0, 100 * dt.asSeconds())))
                                move(sf::Vector2f(0, 100 * dt.asSeconds()));
                }

                if (InputManager::isActive(User_Input::RIGHTHOLD))
                {
                        if (nextPosValid(sf::Vector2f(100 * dt.asSeconds(), 0)))
                                move(sf::Vector2f(100 * dt.asSeconds(), 0));
                }

                if (InputManager::isActive(User_Input::PPRESS))
                {
                        getAttribute<int>("health") -= 5;

                        std::cout << "Player health is now: " << getAttribute<int>("health") << std::endl;
                }

                if (InputManager::isActive(User_Input::VHOLD))
                {
                        if (SceneManager::getView().getSize().x < 300 ||
                                SceneManager::getView().getSize().y < 300)
                                SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x + 0.5, SceneManager::getView().getSize().y + 0.5));
                }

                else if (InputManager::isActive(User_Input::IHOLD))
                {
                        if (SceneManager::getView().getSize().x >= 100 ||
                                SceneManager::getView().getSize().y >= 100)
                                SceneManager::getView().setSize(sf::Vector2f(SceneManager::getView().getSize().x - 0.5, SceneManager::getView().getSize().y - 0.5));
                }

                if (getAttribute<int>("health") <= 0)
                        setAttribute("renderable", new bool(false));

                setPosition(m_sprite.getPosition());
                setBounds(m_sprite.getGlobalBounds());
        }

        void Player::draw(sf::RenderTarget& target, sf::RenderStates states) const
        {
                target.draw(m_sprite, states);
        }

Tilemap.hpp

        class TileMap : public sf::Drawable, public sf::Transformable
        {
        public:
                struct Tile
                {
                        Tile(const sf::FloatRect& bounds, int tileType) : bounds(bounds), tileType(tileType) {};

                        sf::FloatRect bounds;
                        int tileType;
                };

                void load(const std::string& tileSet, sf::Vector2u tileSize, int* tiles,
                        unsigned int width, unsigned int height)
                {
                        m_tileset.loadFromFile(tileSet);

                        m_vertices.setPrimitiveType(sf::Quads);
                        m_vertices.resize(width * height * 4);

                        for (unsigned int i = 0; i < width; ++i)
                        {
                                for (unsigned int j = 0; j < height; ++j)
                                {
                                        int tileNumber = tiles[i + j * width];

                                        sf::Vector2f topLeft(i * tileSize.x, j * tileSize.y);
                                        sf::Vector2f topRight((i + 1) * tileSize.x, j * tileSize.y);
                                        sf::Vector2f downLeft((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                                        sf::Vector2f downRight(i * tileSize.x, (j + 1) * tileSize.y);

                                        sf::FloatRect rect(topLeft.x, topLeft.y, topRight.x - topLeft.x, downLeft.y - topLeft.y);

                                        Tile tile(rect, tileNumber);

                                        m_tiles.push_back(tile);

                                        //Find the position in the tileset texture
                                        int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                                        int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);

                                        sf::Vertex* quad = &m_vertices[(i + j * width) * 4];

                                        //Define its 4 corners
                                        quad[0].position = sf::Vector2f(std::floor(topLeft.x), std::floor(topLeft.y));
                                        quad[1].position = sf::Vector2f(std::floor(topRight.x), std::floor(topRight.y));
                                        quad[2].position = sf::Vector2f(std::floor(downLeft.x), std::floor(downLeft.y));
                                        quad[3].position = sf::Vector2f(std::floor(downRight.x), std::floor(downRight.y));

                                        //Define its 4 texture coordinates
                                        quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                                        quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                                        quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                                        quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
                                }
                        }
                }

                bool collidesWithType(int tileType, const sf::FloatRect& bounds)
                {
                        for (auto& iter : m_tiles)
                        {
                                if (iter.tileType == tileType)
                                {
                                        if (bounds.intersects(iter.bounds))
                                                return true;
                                }
                        }

                        return false;
                }

        private:
                virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
                {
                        states.transform *= getTransform();
                        states.texture = &m_tileset;
                        target.draw(m_vertices, states);
                }

                sf::VertexArray m_vertices;
                sf::Texture m_tileset;

                std::vector<Tile> m_tiles;
        };

As you can see, I tried using std::floor on my views and my tiles, but unfortunately nothing has been working so far.

You bumped... i repeat "Post minimal example that reproduces the error." i don't have time to waste going trough random code.
Meaning, you create a main function and you add intro it ONLY the things you need help with, make it compile and post the code, we will fix it for you.
By doing this you will most likely fix the mistake yourself.

EDIT:: also please, if you want to fix the error, post your specs, os, also did you update gpu drivers?
« Last Edit: August 10, 2014, 06:03:25 pm by BaneTrapper »
BaneTrapperDev@hotmail.com Programing, Coding
Projects: Not in development(unfinished/playable):
http://en.sfml-dev.org/forums/index.php?topic=11073.msg76266#msg76266
UP and in Development: The Wanderer - Lost in time
http://en.sfml-dev.org/forums/index.php?topic=14563.0

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #19 on: August 17, 2014, 04:44:53 pm »
class TileMap : public sf::Drawable, public sf::Transformable
{
public:

    bool load(const std::string& tileset, sf::Vector2u tileSize, const int* tiles, unsigned int width, unsigned int height)
    {
        // load the tileset texture
        if (!m_tileset.loadFromFile(tileset))
            return false;

        // resize the vertex array to fit the level size
        m_vertices.setPrimitiveType(sf::Quads);
        m_vertices.resize(width * height * 4);

        // populate the vertex array, with one quad per tile
        for (unsigned int i = 0; i < width; ++i)
            for (unsigned int j = 0; j < height; ++j)
            {
                // get the current tile number
                int tileNumber = tiles[i + j * width];

                // find its position in the tileset texture
                int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);

                // get a pointer to the current tile's quad
                sf::Vertex* quad = &m_vertices[(i + j * width) * 4];

                // define its 4 corners
                quad[0].position = sf::Vector2f(i * tileSize.x, j * tileSize.y);
                quad[1].position = sf::Vector2f((i + 1) * tileSize.x, j * tileSize.y);
                quad[2].position = sf::Vector2f((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                quad[3].position = sf::Vector2f(i * tileSize.x, (j + 1) * tileSize.y);

                // define its 4 texture coordinates
                quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);
            }

        return true;
    }

private:

    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // apply the transform
        states.transform *= getTransform();

        // apply the tileset texture
        states.texture = &m_tileset;

        // draw the vertex array
        target.draw(m_vertices, states);
    }

    sf::VertexArray m_vertices;
    sf::Texture m_tileset;
};

int main()
{
    // create the window
    sf::RenderWindow window(sf::VideoMode(512, 256), "tilemap");

    // define the level with an array of tile indices
    const int level[] =
    {
        0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
        1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
        0, 1, 0, 0, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0,
        0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 2, 0, 0,
        0, 0, 1, 0, 1, 0, 2, 2, 0, 0, 1, 1, 1, 1, 2, 0,
        2, 0, 1, 0, 1, 0, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1,
        0, 0, 1, 0, 1, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 1,
    };

    // create the tilemap from the level definition
    TileMap map;
    if (!map.load("spritesheet.png", sf::Vector2u(32, 32), level, 16, 8))
        return -1;

    // run the main loop
    while (window.isOpen())
    {
        // handle events
        sf::Event event;
        while (window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        // draw the map
        window.clear();
        window.draw(map);
        window.display();
    }

    return 0;
}

I wanted to attach the spritesheet that I'm using, but unfortunately it doesn't let me attach it to the post. For some reason it says that the upload folder is "full" and I need to contact an administrator, even though the file is only 136 bytes.

Thanks!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Line artifacts when drawing tilemap
« Reply #20 on: August 17, 2014, 05:43:15 pm »
I wanted to attach the spritesheet that I'm using, but unfortunately it doesn't let me attach it to the post. For some reason it says that the upload folder is "full" and I need to contact an administrator, even though the file is only 136 bytes.
And did you contact an administrator? ;)

Luckily I read the message and it seemed that there has been a limit which got copied over from the old system. The limit has now been changed and you should be able again to attache things.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #21 on: August 17, 2014, 05:58:50 pm »
The limit has now been changed and you should be able again to attache things.

Thank you!

And for the people that were kind enough to try to help me, I've attached the spritesheet that I'm using in my engine.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Line artifacts when drawing tilemap
« Reply #22 on: August 18, 2014, 12:02:24 am »
Which problems are you having when you run the complete example that you posted (you forgot the includes :P)?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

DevilEdge

  • Newbie
  • *
  • Posts: 28
    • View Profile
Re: Line artifacts when drawing tilemap
« Reply #23 on: August 18, 2014, 05:33:00 pm »
I finally (somewhat) resolved the issue. VS 13 keeps giving me the bug even with the simple example, but CodeBlocks 13.12 doesn't, so I'm sticking with codeblocks. Thanks to anyone who tried to help!

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Line artifacts when drawing tilemap
« Reply #24 on: August 24, 2014, 07:18:24 pm »
Just so you know, the screenshot that I posted above from your code was generated using VS2013.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

 

anything