The next little game in the series where I make a fancy rogue game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
roguish/scratchpad/img2ansi.cpp

160 lines
3.6 KiB

#include <chrono> // for operator""s, chrono_literals
#include <thread> // for sleep_for
#include <fmt/core.h>
#include <filesystem>
#include "panel.hpp"
#include "color.hpp"
#include "render.hpp"
#include "dbc.hpp"
#include <SFML/Graphics/Image.hpp>
#include <ftxui/screen/color.hpp>
#include <ftxui/screen/terminal.hpp>
#include <iostream>
#include <fcntl.h>
#include <io.h>
#include <vector>
using namespace std::chrono_literals;
using namespace fmt;
using std::string, std::cout, std::vector;
struct HSVColor {
unsigned long h = 0;
unsigned long s = 0;
unsigned long v = 0;
};
struct RGBColor {
unsigned long r = 0;
unsigned long g = 0;
unsigned long b = 0;
};
// taken from https://github.com/python/cpython/blob/3.9/Lib/colorsys.py#L140
HSVColor rgb_to_hsv(sf::Color rgb) {
float r = rgb.r / 255.0f;
float g = rgb.g / 255.0f;
float b = rgb.b / 255.0f;
float maxc = std::max({rgb.r, rgb.g, rgb.b});
float minc = std::min({rgb.r, rgb.g, rgb.b});
float v = maxc;
// if minc == maxc:
if(minc == maxc) {
// no hue no sat, so gray with value
return {0, 0, uint8_t(v * 255.0)};
}
float s = (maxc - minc) / maxc;
float rc = (maxc - r) / (maxc - minc);
float gc = (maxc - g) / (maxc - minc);
float bc = (maxc - b) / (maxc - minc);
float h = 0.0f;
if(r == maxc) {
h = bc-gc;
} else if(g == maxc) {
h = 2.0 + rc - bc;
} else {
h = 4.0 + gc - rc;
h = std::fmod((h/6.0), 1.0);
}
return {uint8_t(h * 255.0f), uint8_t(s * 255.0f), uint8_t(v * 255.0f)};
}
int main(int argc, char *argv[]) {
ftxui::Terminal::SetColorSupport(ftxui::Terminal::Color::TrueColor);
_setmode(_fileno(stdout), _O_U16TEXT);
dbc::check(argc == 2, "USAGE: img2ansi <image_file>");
string image_file(argv[1]);
println("LOADING IMAGE: {}", image_file);
// load the image from argv
sf::Image image;
image.loadFromFile(image_file);
// divide the image into cells
auto size = image.getSize();
const int cell = 3;
// create a grid panel to hold the cells
Panel panel(0, 0, 0, 0, true);
println("IMAGE SIZE {},{}", size.x, size.y);
RGBColor avg{0,0,0};
typedef vector<RGBColor> ColorRow;
vector<ColorRow> colors(size.x / cell, ColorRow(size.y / cell));
// LOL, so bad but just the start
for(unsigned int i = 0; i < size.x / cell; i++) {
for(unsigned int j = 0; j < size.y / cell; j++) {
// sum the cell
for(unsigned int x = 0; x < cell ; x++) {
for(unsigned int y = 0; y < cell ; y++) {
auto pixel = image.getPixel((i*cell) + x, (j * cell) + y);
avg.r += pixel.r;
avg.g += pixel.g;
avg.b += pixel.b;
}
}
// average it for the cell size
RGBColor color = {avg.r / (cell * cell),
avg.g / (cell * cell), avg.b / (cell * cell)};
// add it
colors[i][j] = color;
// reset
avg = {0,0,0};
}
}
Canvas drawing;
SFMLRender renderer;
if(renderer.resize_grid(10, panel)) {
drawing = Canvas(panel.width * 2, panel.height * 4);
}
panel.set_renderer(Renderer([&]{
for(size_t x = 0; x < colors.size(); x++) {
for(size_t y = 0; y < colors[0].size(); y++) {
auto color = colors[x][y];
ftxui::Color block = ftxui::Color::RGB(color.r, color.g, color.b);
drawing.DrawText(x * 2, y * 4, "", block);
}
}
return ftxui::canvas(drawing);
}));
sf::Event event;
while(renderer.is_open()) {
renderer.draw(panel);
renderer.display();
while(renderer.poll_event(event)) {
if(event.type == sf::Event::Closed) {
renderer.close();
}
}
std::this_thread::sleep_for(100ms);
}
return 0;
}