/** roflcat Copyright (C) 2019 rexy712 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef COLOR_PRINTER_TRUE_HPP #define COLOR_PRINTER_TRUE_HPP #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE //for wcwidth #endif #include //wcwidth #include "cmd.hpp" #include "color_printer_base.hpp" #include //std::abs #include //std::min, std::max #include //wprintf, putwchar //True color printer. Too many options to enumerate the entire list of possible colors, so we calculate on the fly class color_printer_true : public color_printer_base { friend class printer_base; private: static constexpr const char* lookup_table[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255"}; static constexpr long lookup_table_len = sizeof(lookup_table)/sizeof(lookup_table[0]); static constexpr int color_min_amount = 20; static constexpr int color_max_amount = 255; enum class color{ red, green, blue }; struct color_state{ int r = color_min_amount, g = color_min_amount, b = color_max_amount; color curr = color::red; constexpr color_state(void)noexcept = default; constexpr color inc(void){ switch(curr){ default: case color::red: return (curr = color::green); case color::green: return (curr = color::blue); case color::blue: return (curr = color::red); }; } constexpr color dec(void){ switch(curr){ default: case color::red: return (curr = color::blue); case color::green: return (curr = color::red); case color::blue: return (curr = color::green); }; } }m_line_color = {}, m_color = {}; public: constexpr color_printer_true(const cmd_args& args)noexcept: color_printer_base(args){} protected: color_printer_true& _print(const wchar_t s)noexcept{ bool updated = false; if(s == L'\n'){ inc_line(); updated = true; }else{ int width = wcwidth(s); if(width > 0) updated = inc_color(wcwidth(s)); else updated = inc_color(1); } if(updated) wprintf(L"\033[38;2;%s;%s;%sm", lookup_table[m_color.r], lookup_table[m_color.g], lookup_table[m_color.b]); putwchar(s); return *this; } constexpr void inc_line(void){ int amount = m_spread*(float{color_max_amount}/4); _do_inc_color(amount, m_line_color); m_color = m_line_color; } constexpr bool inc_color(int i){ int amount = i*m_freq*(float{color_max_amount}/4); if(amount == 0) return false; _do_inc_color(amount, m_color); return true; } constexpr static void _do_inc_color(int amount, color_state& c){ int* curr = nullptr, *next = nullptr, *prev = nullptr; color (color_state::*inc)(void) = nullptr; if(amount > 0){ inc = &color_state::inc; switch(c.curr){ default: case color::red: curr = &c.r; prev = &c.b; next = &c.g; break; case color::green: curr = &c.g; prev = &c.r; next = &c.b; break; case color::blue: curr = &c.b; prev = &c.g; next = &c.r; break; }; }else{ inc = &color_state::dec; switch(c.curr){ default: case color::red: curr = &c.b; prev = &c.r; next = &c.g; break; case color::green: curr = &c.r; prev = &c.g; next = &c.b; break; case color::blue: curr = &c.g; prev = &c.b; next = &c.r; break; }; } amount = std::abs(amount); while(amount != 0){ int old = *curr; *curr = std::min((*curr)+amount, color_max_amount); amount = (old+amount)-(*curr); old = *prev; *prev = std::max((*prev)-amount, color_min_amount); amount = (amount-old)+(*prev); if((*prev) == color_min_amount){ (c.*inc)(); int* tmp = curr; curr = next;next = prev;prev = tmp; } } } }; #endif