feat: add support for color and buffer shading
This commit is contained in:
parent
b5868dfdec
commit
c6238f2e1c
@ -1,34 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "vec.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#include <functional>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <vector>
|
||||
|
||||
struct Screen {
|
||||
char *buf;
|
||||
/**
|
||||
* Unit pixel information struct
|
||||
*/
|
||||
struct Symbol {
|
||||
char sym;
|
||||
vec<3> color = {0,0,0};
|
||||
bool visible = true;
|
||||
|
||||
Symbol &operator=(char c) { sym = c; return *this; };
|
||||
};
|
||||
|
||||
/**
|
||||
* Function taking screen coords and space coords and returning a Symbol for
|
||||
* that position
|
||||
*/
|
||||
using char_shader_t = std::function<Symbol(int, int, float, float)>;
|
||||
|
||||
std::size_t w, h;
|
||||
|
||||
float dx = 0, dy = 0;
|
||||
float sx = 1, sy = 1;
|
||||
float sx = 1, sy = 1.8;
|
||||
|
||||
void draw();
|
||||
void clear();
|
||||
|
||||
char &at(std::size_t n);
|
||||
char &at(std::size_t x, std::size_t y);
|
||||
Symbol &at(std::size_t n);
|
||||
Symbol &at(int x, int y);
|
||||
Symbol &at(float x, float y);
|
||||
|
||||
void resize(std::size_t n);
|
||||
void resize(std::size_t x, std::size_t y);
|
||||
|
||||
std::pair<float, float> screen_to_xy(int w, int h);
|
||||
std::pair<int, int> xy_to_screen(float x, float y);
|
||||
|
||||
Screen(std::size_t n) : buf(nullptr) { resize(n); }
|
||||
Screen(std::size_t x, std::size_t y) : buf(nullptr) { resize(x, y); }
|
||||
~Screen() { delete[] buf; }
|
||||
|
||||
std::vector<const vec<2>*> points;
|
||||
char_shader_t shader;
|
||||
|
||||
private:
|
||||
char _dummy;
|
||||
Symbol *buf;
|
||||
Symbol _dummy;
|
||||
|
||||
static inline void gotoxy(int x, int y)
|
||||
{
|
||||
@ -36,6 +63,19 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
using colorizer_t = std::function<vec<3>(float)>;
|
||||
|
||||
struct TanhColorizer {
|
||||
float scale = 1.0;
|
||||
float translate = 0.0;
|
||||
vec<3> operator()(float y);
|
||||
|
||||
private:
|
||||
static vec<3> hsl_to_rgb(float h, float s, float l);
|
||||
static float hue_to_rgb(float p, float q, float t);
|
||||
};
|
||||
|
||||
|
||||
static termios old, current;
|
||||
static inline void enter_noncanonical_mode(void)
|
||||
{
|
||||
|
@ -2,33 +2,113 @@
|
||||
#include <cstring>
|
||||
#include <screen.hpp>
|
||||
|
||||
/* Screen */
|
||||
|
||||
void Screen::resize(std::size_t n) {
|
||||
w = n; h = 1;
|
||||
buf = (char *)realloc(buf, n * sizeof(char));
|
||||
buf = (Symbol *)realloc(buf, n * sizeof(Symbol));
|
||||
}
|
||||
|
||||
void Screen::resize(std::size_t x, std::size_t y) {
|
||||
w = x; h = y;
|
||||
buf = (char *)realloc(buf, x * y * sizeof(char));
|
||||
buf = (Symbol *)realloc(buf, x * y * sizeof(Symbol));
|
||||
}
|
||||
|
||||
char &Screen::at(std::size_t n) { return buf[n]; }
|
||||
char &Screen::at(std::size_t x, std::size_t y) {
|
||||
auto idx = (int)(((y-dy)/sy) * w) + (int)((x-dx)/sx);
|
||||
if(idx >= w *h) return _dummy;
|
||||
Screen::Symbol &Screen::at(std::size_t n) { return buf[n]; }
|
||||
Screen::Symbol &Screen::at(int x, int y) {
|
||||
auto idx = y * w + x;
|
||||
if(idx < 0 || idx >= w * h) return _dummy;
|
||||
return buf[idx];
|
||||
}
|
||||
|
||||
Screen::Symbol &Screen::at(float x, float y) {
|
||||
auto [a, b] = xy_to_screen(x, y);
|
||||
if(a < 0 || a >= w || b < 0 || b >= h) return _dummy;
|
||||
return at(a, b);
|
||||
}
|
||||
|
||||
std::pair<float, float> Screen::screen_to_xy(int x, int y) {
|
||||
return {
|
||||
x * sx + dx,
|
||||
y * sy + dy
|
||||
};
|
||||
}
|
||||
|
||||
std::pair<int, int> Screen::xy_to_screen(float x, float y) {
|
||||
return {
|
||||
(x - dx)/sx,
|
||||
(y - dy)/sy
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void Screen::clear() {
|
||||
memset(buf, ' ', w*h);
|
||||
static const Symbol s {' ', {0,0,0}};
|
||||
for(int i = 0; i < w * h; ++i)
|
||||
memcpy(buf + i, &s, sizeof(Symbol));
|
||||
}
|
||||
|
||||
void Screen::draw() {
|
||||
// "shade" each pixel on screen with #this->shader()
|
||||
for(int i = 0; i < h; ++i) {
|
||||
for(int j = 0; j < w; ++j) {
|
||||
auto [x, y] = screen_to_xy(j, i);
|
||||
at(j, i) = shader(j, i, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// write out a '#' wherever we have a point registered
|
||||
for(const auto &p : points) {
|
||||
at(p->x, p->y) = {.sym = '#', .color = 1};
|
||||
}
|
||||
|
||||
// print out each symbol in our buffer to the terminal
|
||||
gotoxy(0, 0);
|
||||
for(int i = 0; i < h; ++i) {
|
||||
for(int j = 0; j < w; ++j) {
|
||||
std::fputc(at(j, i), stdout);
|
||||
const auto &sym = at(j, i);
|
||||
const auto color = sym.color.clamp({0,0,0}, {1,1,1}) * 255;
|
||||
printf("\033[48;2;%d;%d;%dm%c",
|
||||
(int)color.x, (int)color.y, (int)color.z, sym.sym);
|
||||
}
|
||||
std::fputc('\n', stdout);
|
||||
|
||||
// reset color, go to the next line
|
||||
printf("\033[38;2;%d;%d;%dm\n", 0,0,0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* TanhColorizer */
|
||||
|
||||
vec<3> TanhColorizer::operator()(float y) {
|
||||
y = (std::tanh((y - translate)/scale * 2.25) + 1)/2.f;
|
||||
float hue = (1.f - y) * 240.f / 360.f;
|
||||
return hsl_to_rgb(hue, 1, 0.5);
|
||||
}
|
||||
|
||||
vec<3> TanhColorizer::hsl_to_rgb(float h, float s, float l) {
|
||||
float q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
float p = 2 * l - q;
|
||||
float r = hue_to_rgb(p, q, h + 0.33);
|
||||
float g = hue_to_rgb(p, q, h);
|
||||
float b = hue_to_rgb(p, q, h - 0.33);
|
||||
return { r, g, b };
|
||||
}
|
||||
|
||||
float TanhColorizer::hue_to_rgb(float p, float q, float t) {
|
||||
if (t < 0) {
|
||||
t += 1;
|
||||
} else if (t > 1) {
|
||||
t -= 1;
|
||||
}
|
||||
|
||||
if (t >= 0.66) {
|
||||
return p;
|
||||
} else if (t >= 0.5) {
|
||||
return p + (q - p) * (0.66 - t) * 6;
|
||||
} else if (t >= 0.33) {
|
||||
return q;
|
||||
} else {
|
||||
return p + (q - p) * 6 * t;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user