#include <SFML/Graphics.hpp>
#include <cstdlib>
#include <ctime>
#include <map>

int main()
{
    std::srand(std::time(0));

    const int width  = 512;
    const int height = 256;

    sf::Image image(width, height, sf::Color::White);

    image.SetSmooth(false);

    std::map<int, int> interiorId2offset;

    for (int i = 0; i < width; ++ i) {
        for (int j = 0; j < height; ++ j) {

            int val = 0;
            int offset = 0;

            if (j % 128 < 64)
                offset = 40;

            bool one = ((i + offset) % 128 < 2 || (i + offset) % 128 > 126);
            bool two = ( j           %  64 < 2 ||  j           %  64 >  62);

            bool nearOne = (i % 128 < 8 || i % 128 > 120);
            bool nearTwo = (j %  64 < 8 || j %  64 >  56);

            if (one && !nearTwo)
                val = 225;

            if (two && !nearOne)
                val = 225;

            bool interior = !one && !two;

            if (interior) {

                int x = (i + offset) / 128;
                int y =  j           /  64;

                if (x >= width / 128) x = 0; // in order to be tileable

                int interiorOffset = interiorId2offset[x + 100 * y];

                if (interiorOffset == 0) {

                    interiorOffset = std::rand() % 3 * 30 + 1;
                    interiorId2offset[x + 100 * y] = interiorOffset;
                }

                val = ((i + offset) % 128 + j % 64 + interiorOffset) % 256;

                if (val <  25) val =  25;
                if (val > 175) val = 175;
            }

            image.SetPixel(i, j, sf::Color(val, val, val));
        }
    }

    sf::Sprite sprite(image);

    sf::RenderWindow window(sf::VideoMode(width * 2, height * 2, 32), "Procedural Textures!");

    window.UseVerticalSync(true);

    bool Running = true;

    while (Running)
    {
        sf::Event Event;

        while (window.GetEvent(Event))
        {
            if (Event.Type == sf::Event::Closed)
                Running = false;

            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
                Running = false;
        }

        window.Clear();

        window.Draw(sprite);
        sprite.Move(width, 0);
        window.Draw(sprite);
        sprite.Move(0, height);
        window.Draw(sprite);
        sprite.Move(- width, 0);
        window.Draw(sprite);
        sprite.Move(0, - height);

        window.Display();
    }
}