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

177 lines
4.1 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 Point cell = {3, 6};
println("IMAGE SIZE {},{}", size.x, size.y);
RGBColor avg{0,0,0};
typedef vector<RGBColor> ColorRow;
vector<ColorRow> colors(size.x / cell.x, ColorRow(size.y / cell.y));
// LOL, so bad but just the start
for(unsigned int i = 0; i < size.x / cell.x; i++) {
for(unsigned int j = 0; j < size.y / cell.y; j++) {
// sum the cell
for(unsigned int x = 0; x < cell.x ; x++) {
for(unsigned int y = 0; y < cell.y ; y++) {
auto pixel = image.getPixel((i*cell.x) + x, (j * cell.y) + y);
avg.r += pixel.r;
avg.g += pixel.g;
avg.b += pixel.b;
}
}
// average it for the cell size
RGBColor color = {
avg.r / int(cell.x * cell.y),
avg.g / int(cell.x * cell.y),
avg.b / int(cell.x * cell.y),
};
// add it
colors[i][j] = color;
// reset
avg = {0,0,0};
}
}
Canvas drawing;
// create a grid panel to hold the cells
Panel panel(0, 0, 0, 0, true);
SFMLRender renderer;
renderer.resize_grid(26, panel);
drawing = Canvas(panel.width * 2, panel.height * 4);
panel.resize(240,240);
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;
int start_x = 0;
int start_y = 0;
int end_x = 600;
int end_y = 300;
int cur_x = start_x;
int cur_y = start_y;
sf::Texture texture;
texture.loadFromFile(image_file);
sf::Sprite sprite(texture);
panel.render();
while(renderer.is_open()) {
cur_x = cur_x < end_x ? cur_x + 1 : start_x;
cur_y = cur_y < end_y ? cur_y + 1 : start_y;
// sprite.setPosition(cur_x, cur_y);
// renderer.$window.draw(sprite);
// renderer.display();
renderer.draw(panel, cur_x, cur_y);
renderer.display();
while(renderer.poll_event(event)) {
if(event.type == sf::Event::Closed) {
renderer.close();
}
}
}
return 0;
}