diff --git a/include/screen.hpp b/include/screen.hpp index cc6456e..ad3b758 100644 --- a/include/screen.hpp +++ b/include/screen.hpp @@ -1,34 +1,61 @@ #pragma once +#include "vec.hpp" #include #include #include +#include #include #include +#include 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; + 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 screen_to_xy(int w, int h); + std::pair 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*> 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(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) { diff --git a/src/screen.cpp b/src/screen.cpp index 68ddca9..a969003 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -2,33 +2,113 @@ #include #include +/* 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 Screen::screen_to_xy(int x, int y) { + return { + x * sx + dx, + y * sy + dy + }; +} + +std::pair 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; } }