#include "config.h" #include #include #include #include #include #include #include #include "brushes.h" namespace fs = std::filesystem; namespace { bool seeded = false; std::mt19937 engine; std::uniform_int_distribution color_dist; std::uniform_real_distribution white_chance(0, 1.0); sf::Color random_color() { if (!seeded) { engine.seed(std::random_device{}()); seeded = true; } #define COLOR_MODE 2 #if (COLOR_MODE == 1) sf::Color c = sf::Color(color_dist(engine)); c.a = 255; c.g = 0; return c; #elif (COLOR_MODE == 2) sf::Color c = white_chance(engine) > 0.5 ? sf::Color::Yellow : sf::Color::Green; float f = white_chance(engine); c.r *= f; c.g *= f; c.b *= f; c.a = 255; return c; #elif (COLOR_MODE == 3) if (white_chance(engine) > 0.5) { return sf::Color::White; } else { return sf::Color::Black; } #elif (COLOR_MODE == 4) float f = white_chance(engine); return sf::Color(255 * f, 255 * f, 255 * f, 255); #endif } // Distort a black-white color. assume color_mode == 3 or 4. sf::Color distort(const sf::Color& c, float p = 2) { return sf::Color(255 * std::pow(c.r / 255.0, p), 255 * std::pow(c.g / 255.0, p), 255 * std::pow(c.b / 255.0, p), 255); } bool in_range(const sf::Vector2u& size, const sf::Vector2u& v) { return v.x < size.x && v.y < size.y; } sf::Color avg_color(const sf::Image& im, unsigned i, unsigned j, const std::vector& d, bool black_border = false) { sf::Vector2u p(i, j); unsigned long ct = 0, r = 0, g = 0, b = 0, a = 0; for (int k = 0; k < d.size(); ++k) { sf::Vector2u q = p + sf::Vector2u(d[k]); if (in_range(im.getSize(), q)) { r += im.getPixel(q.x, q.y).r * (p == q ? 2 : 1); g += im.getPixel(q.x, q.y).g * (p == q ? 2 : 1); b += im.getPixel(q.x, q.y).b * (p == q ? 2 : 1); a += im.getPixel(q.x, q.y).a; ct += (p == q ? 2 : 1); } else if (black_border) { ++ct; } } r /= ct; g /= ct; b /= ct; a /= ct; return sf::Color(r, g, b, a); } sf::Color avg_card(const sf::Image& im, unsigned i, unsigned j) { const std::vector d = { {0, 0}, {1, 0}, {0, -1}, {-1, 0}, {0, 1}}; return avg_color(im, i, j, d); } void noise(sf::Image& im, int mode) { sf::Image im2, im3; if (mode == 1) { im2.create(im.getSize().x * 2, im.getSize().y * 2); for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { sf::Color c = im.getPixel(i, j); im2.setPixel(i * 2, j * 2, c); im2.setPixel(i * 2 + 1, j * 2, c); im2.setPixel(i * 2 + 1, j * 2 + 1, c); im2.setPixel(i * 2, j * 2 + 1, c); } } im3.create(im.getSize().x * 2, im.getSize().y * 2); for (unsigned i = 0; i < im2.getSize().x; ++i) { for (unsigned j = 0; j < im2.getSize().y; ++j) { im3.setPixel(i, j, brushes::CardinalAverage(im2, i, j)); } } } else if (mode == 2) { im3.create(im.getSize().x, im.getSize().y); for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { im3.setPixel(i, j, brushes::CardinalAverage(im, i, j)); } } } else if (mode == 3) { im3.create(im.getSize().x * 2, im.getSize().y * 2); for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { sf::Color c = im.getPixel(i, j); im3.setPixel(i * 2, j * 2, c); im3.setPixel(i * 2 + 1, j * 2, avg_color(im, i, j, {{0, 0}, {1, 0}}, true)); im3.setPixel(i * 2, j * 2 + 1, avg_color(im, i, j, {{0, 0}, {0, 1}}, true)); im3.setPixel(i * 2 + 1, j * 2 + 1, avg_color(im3, i * 2 + 1, j * 2 + 1, {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1,-1},{-1,1},{1,-1},{1,1}}, true)); } } } else { throw std::invalid_argument("Bad noise mode."); } im = im3; } sf::Color flip(const sf::Color& c) { return sf::Color(255 - c.r, 255 - c.g, 255 - c.b, c.a); } } // namespace int main(int argc, char* argv[]) { sf::RenderWindow window(sf::VideoMode(640, 400), "Noise"); sf::Font font; if (!font.loadFromFile((fs::path(argv[0]).parent_path() / "OpenSans.ttf").string())) { std::cerr << "FATAL: Failed to load font OpenSans.ttf." << std::endl; return -1; } #ifdef HAVE_FONT_SMOOTHING font.setSmooth(true); #endif sf::Text counter("Iteration 0 Blur 0 Brightness 0", font); counter.setPosition(5, 5); sf::Text help( "1 - Zoom\tQ - Quit\n" "2 - Average blur\n" "3 - Quadratic darken\n" "4 - Quadratic brighten\n" "F - Flip colors\n" "R - randomize pixels\n" "0 - Reset texture", font, 15); help.setPosition(5, window.getSize().y - help.getLocalBounds().height - 10); int icount = 0, bcount = 0, dcount = 0; sf::Texture text; sf::Image im; sf::RectangleShape rect(sf::Vector2f(400, 200)); rect.setPosition(100, 50); const sf::Vector2u initSize(32, 16); im.create(initSize.x, initSize.y, sf::Color::White); for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { im.setPixel(i, j, random_color()); } } text.loadFromImage(im); rect.setTexture(&text); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } else if (event.type == sf::Event::KeyReleased) { if (event.key.code == sf::Keyboard::Num1 && im.getSize().x < 2 << 8) { ++icount; noise(im, 1); } else if (event.key.code == sf::Keyboard::Num2) { ++bcount; if (event.key.shift) { } else { noise(im, 2); } } else if (event.key.code == sf::Keyboard::Num3) { --dcount; for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { im.setPixel(i, j, distort(im.getPixel(i, j), 1.5)); } } } else if (event.key.code == sf::Keyboard::Num4) { ++dcount; for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { im.setPixel(i, j, distort(im.getPixel(i, j), 2.0 / 3)); } } } else if (event.key.code == sf::Keyboard::F) { for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { im.setPixel(i, j, flip(im.getPixel(i, j))); } } } else if (event.key.code == sf::Keyboard::Num0) { bcount = icount = 0, dcount = 0; im.create(initSize.x, initSize.y, sf::Color::White); for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { im.setPixel(i, j, random_color()); } } } else if (event.key.code == sf::Keyboard::R) { bcount = 0, dcount = 0; for (unsigned i = 0; i < im.getSize().x; ++i) { for (unsigned j = 0; j < im.getSize().y; ++j) { im.setPixel(i, j, random_color()); } } } else { continue; } counter.setString("Iteration " + std::to_string(icount) + " Blur " + std::to_string(bcount) + " Brightness " + std::to_string(dcount)); text.loadFromImage(im); rect.setTexture(&text, true); } } window.clear(); window.draw(help); window.draw(counter); window.draw(rect); window.display(); sf::sleep(sf::milliseconds(1)); } return 0; }