feat: add support for color and buffer shading
This commit is contained in:
parent
b5868dfdec
commit
c6238f2e1c
@ -1,34 +1,61 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "vec.hpp"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct Screen {
|
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;
|
std::size_t w, h;
|
||||||
|
|
||||||
float dx = 0, dy = 0;
|
float dx = 0, dy = 0;
|
||||||
float sx = 1, sy = 1;
|
float sx = 1, sy = 1.8;
|
||||||
|
|
||||||
void draw();
|
void draw();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
char &at(std::size_t n);
|
Symbol &at(std::size_t n);
|
||||||
char &at(std::size_t x, std::size_t y);
|
Symbol &at(int x, int y);
|
||||||
|
Symbol &at(float x, float y);
|
||||||
|
|
||||||
void resize(std::size_t n);
|
void resize(std::size_t n);
|
||||||
void resize(std::size_t x, std::size_t y);
|
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 n) : buf(nullptr) { resize(n); }
|
||||||
Screen(std::size_t x, std::size_t y) : buf(nullptr) { resize(x, y); }
|
Screen(std::size_t x, std::size_t y) : buf(nullptr) { resize(x, y); }
|
||||||
~Screen() { delete[] buf; }
|
~Screen() { delete[] buf; }
|
||||||
|
|
||||||
|
std::vector<const vec<2>*> points;
|
||||||
|
char_shader_t shader;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char _dummy;
|
Symbol *buf;
|
||||||
|
Symbol _dummy;
|
||||||
|
|
||||||
static inline void gotoxy(int x, int y)
|
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 termios old, current;
|
||||||
static inline void enter_noncanonical_mode(void)
|
static inline void enter_noncanonical_mode(void)
|
||||||
{
|
{
|
||||||
|
@ -2,33 +2,113 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <screen.hpp>
|
#include <screen.hpp>
|
||||||
|
|
||||||
|
/* Screen */
|
||||||
|
|
||||||
void Screen::resize(std::size_t n) {
|
void Screen::resize(std::size_t n) {
|
||||||
w = n; h = 1;
|
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) {
|
void Screen::resize(std::size_t x, std::size_t y) {
|
||||||
w = x; h = 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]; }
|
Screen::Symbol &Screen::at(std::size_t n) { return buf[n]; }
|
||||||
char &Screen::at(std::size_t x, std::size_t y) {
|
Screen::Symbol &Screen::at(int x, int y) {
|
||||||
auto idx = (int)(((y-dy)/sy) * w) + (int)((x-dx)/sx);
|
auto idx = y * w + x;
|
||||||
if(idx >= w *h) return _dummy;
|
if(idx < 0 || idx >= w * h) return _dummy;
|
||||||
return buf[idx];
|
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() {
|
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() {
|
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);
|
gotoxy(0, 0);
|
||||||
for(int i = 0; i < h; ++i) {
|
for(int i = 0; i < h; ++i) {
|
||||||
for(int j = 0; j < w; ++j) {
|
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