diff --git a/src/modules/main/console.cpp b/src/modules/main/console.cpp index 927f9ec..a71c6b2 100644 --- a/src/modules/main/console.cpp +++ b/src/modules/main/console.cpp @@ -1,22 +1,77 @@ #include "console.h" +const char digits[] = "0123456789abcdef"; + console::console(const font &f, const screen &s, void *scratch, size_t len) : m_font(f), m_screen(s), m_size(s.width() / f.width(), s.height() / f.height()), - m_fg(0xffffffff), - m_bg(0x00000000), + m_fg(0xffffff), + m_bg(0), m_first(0), m_length(len), - m_data(static_cast(scratch)) + m_data(nullptr), + m_attrs(nullptr), + m_palette(nullptr) { - if (len < m_size.size()) { - m_data = nullptr; + const unsigned count = m_size.size(); + const size_t palette_size = sizeof(screen::pixel_t) * 256; + const size_t attrs_size = 2 * count; + + if (len >= count) { + // We have enough scratch space to keep the contents of the screen + m_data = static_cast(scratch); + for (unsigned i = 0; i < count; ++i) + m_data[i] = 0; + } + + if (len >= count + palette_size + attrs_size) { + // We have enough scratch space to also keep the colors of the text + m_palette = reinterpret_cast(m_data + count); + + unsigned index = 0; + + // Manually add the 16 basic ANSI colors + m_palette[index++] = m_screen.color(0x00, 0x00, 0x00); + m_palette[index++] = m_screen.color(0xcd, 0x00, 0x00); + m_palette[index++] = m_screen.color(0x00, 0xcd, 0x00); + m_palette[index++] = m_screen.color(0xcd, 0xcd, 0x00); + m_palette[index++] = m_screen.color(0x00, 0x00, 0xee); + m_palette[index++] = m_screen.color(0xcd, 0x00, 0xcd); + m_palette[index++] = m_screen.color(0x00, 0xcd, 0xcd); + m_palette[index++] = m_screen.color(0xe5, 0xe5, 0xe5); + m_palette[index++] = m_screen.color(0x7f, 0x7f, 0x7f); + m_palette[index++] = m_screen.color(0xff, 0x00, 0x00); + m_palette[index++] = m_screen.color(0x00, 0xff, 0x00); + m_palette[index++] = m_screen.color(0xff, 0xff, 0x00); + m_palette[index++] = m_screen.color(0x00, 0x50, 0xff); + m_palette[index++] = m_screen.color(0xff, 0x00, 0xff); + m_palette[index++] = m_screen.color(0x00, 0xff, 0xff); + m_palette[index++] = m_screen.color(0xff, 0xff, 0xff); + + // Build the high-color portion of the table + const uint32_t intensity[] = {0, 0x5f, 0x87, 0xaf, 0xd7, 0xff}; + const uint32_t intensities = sizeof(intensity) / sizeof(uint32_t); + + for (uint32_t r = 0; r < intensities; ++r) { + for (uint32_t g = 0; g < intensities; ++g) { + for (uint32_t b = 0; b < intensities; ++b) { + m_palette[index++] = m_screen.color( + intensity[r], intensity[g], intensity[b]); + } + } + } + + // Build the greyscale portion of the table + for (uint8_t i = 0x08; i <= 0xee; i += 10) + m_palette[index++] = m_screen.color(i, i, i); + + set_color(7, 0); // Grey on black default + m_attrs = reinterpret_cast(m_data + count + palette_size); + for (unsigned i = 0; i < count; ++i) + m_attrs[i] = m_attr; } - const unsigned count = m_size.size(); - for (unsigned i = 0; i < count; ++i) - m_data[i] = 0; repaint(); } @@ -27,6 +82,13 @@ console::line_pointer(unsigned line) return m_data + ((m_first + line) % m_size.y) * m_size.x; } +uint16_t * +console::attr_pointer(unsigned line) +{ + if (!m_attrs) return nullptr; + return m_attrs + ((m_first + line) % m_size.y) * m_size.x; +} + void console::repaint() { @@ -35,7 +97,13 @@ console::repaint() for (unsigned y = 0; y < m_size.y; ++y) { const char *line = line_pointer(y); + const uint16_t *attrs = attr_pointer(y); for (unsigned x = 0; x < m_size.x; ++x) { + const uint16_t attr = attrs[x]; + + set_color(static_cast(attr), + static_cast(attr >> 8)); + m_font.draw_glyph( m_screen, line[x] ? line[x] : ' ', @@ -47,6 +115,16 @@ console::repaint() } } +void +console::set_color(uint8_t fg, uint8_t bg) +{ + if (!m_palette) return; + + m_bg = m_palette[bg]; + m_fg = m_palette[fg]; + m_attr = (bg << 8) | fg; +} + void console::scroll(unsigned lines) { @@ -69,11 +147,14 @@ size_t console::puts(const char *message) { char *line = line_pointer(m_pos.y); + uint16_t *attrs = attr_pointer(m_pos.y); + size_t count = 0; while (message && *message) { const unsigned x = m_pos.x * m_font.width(); const unsigned y = m_pos.y * m_font.height(); const char c = *message++; + ++count; switch (c) { case '\t': @@ -90,7 +171,8 @@ console::puts(const char *message) break; default: - if (m_data) line[m_pos.x] = c; + if (line) line[m_pos.x] = c; + if (attrs) attrs[m_pos.x] = m_attr; m_font.draw_glyph(m_screen, c, m_fg, m_bg, x, y); m_pos.x++; } @@ -105,5 +187,8 @@ console::puts(const char *message) line = line_pointer(m_pos.y); } } + + return count; } + diff --git a/src/modules/main/console.h b/src/modules/main/console.h index 60b2d3f..11fb01a 100644 --- a/src/modules/main/console.h +++ b/src/modules/main/console.h @@ -14,22 +14,46 @@ public: void repaint(); void scroll(unsigned lines); + void set_color(uint8_t fg, uint8_t bg); + size_t puts(const char *message); size_t printf(const char *fmt, ...); + template + void put_hex(T x); + + void put_dec(uint32_t x); + private: char * line_pointer(unsigned line); + uint16_t * attr_pointer(unsigned line); font m_font; screen m_screen; coord m_size; coord m_pos; - screen::pixel_t m_fg; - screen::pixel_t m_bg; + screen::pixel_t m_fg, m_bg; + uint16_t m_attr; size_t m_first; size_t m_length; char *m_data; + uint16_t *m_attrs; + screen::pixel_t *m_palette; }; + +extern const char digits[]; + +template +void console::put_hex(T x) +{ + static const int chars = sizeof(x) * 2; + char message[chars + 1]; + for (int i=0; i> (i*4)) & 0xf]; + } + message[chars] = 0; + puts(message); +} diff --git a/src/modules/main/main.cpp b/src/modules/main/main.cpp index d25f2d8..76b131a 100644 --- a/src/modules/main/main.cpp +++ b/src/modules/main/main.cpp @@ -11,10 +11,10 @@ extern "C" { void kernel_main(popcorn_data *header); } -void -kernel_main(popcorn_data *header) +console +load_console(const popcorn_data *header) { - console cons{ + return console{ font::load(header->font), screen{ header->frame_buffer, @@ -25,10 +25,17 @@ kernel_main(popcorn_data *header) header->bmask}, header->log, header->log_length}; +} - const int times = 50; +void +kernel_main(popcorn_data *header) +{ + console cons = load_console(header); + + const int times = 38; char message[] = " 000 Hello, I am text rendered by the kernel! :-D\n"; for (int i = 0; i < times; ++i) { + cons.set_color(i, 0); message[1] = '0' + ((i / 100) % 10); message[2] = '0' + ((i / 10) % 10); message[3] = '0' + (i % 10); diff --git a/src/modules/main/screen.cpp b/src/modules/main/screen.cpp index 458a4fe..da645f6 100644 --- a/src/modules/main/screen.cpp +++ b/src/modules/main/screen.cpp @@ -1,7 +1,40 @@ #include "screen.h" -screen::color_masks::color_masks(pixel_t r, pixel_t g, pixel_t b) : r(r), g(g), b(b) {} -screen::color_masks::color_masks(const color_masks &o) : r(o.r), g(o.g), b(o.b) {} +template +static int popcount(T x) +{ + int c = 0; + while (x) { + c += (x & 1); + x = x >> 1; + } + return c; +} + +template +static int ctz(T x) +{ + int c = 0; + while ((x & 1) == 0) { + x = x >> 1; + ++c; + } + return c; +} + +screen::color_masks::color_masks(pixel_t r, pixel_t g, pixel_t b) : + r(r), g(g), b(b) +{ + rshift = static_cast(ctz(r) - (8 - popcount(r))); + gshift = static_cast(ctz(g) - (8 - popcount(g))); + bshift = static_cast(ctz(b) - (8 - popcount(b))); +} + +screen::color_masks::color_masks(const color_masks &o) : + rshift(o.rshift), gshift(o.gshift), bshift(o.bshift), + r(o.r), g(o.g), b(o.b) +{ +} screen::screen( void *framebuffer, @@ -20,6 +53,15 @@ screen::screen(const screen &other) : { } +screen::pixel_t +screen::color(uint8_t r, uint8_t g, uint8_t b) const +{ + return + ((static_cast(r) << m_masks.rshift) & m_masks.r) | + ((static_cast(g) << m_masks.gshift) & m_masks.g) | + ((static_cast(b) << m_masks.bshift) & m_masks.b); +} + void screen::fill(pixel_t color) { diff --git a/src/modules/main/screen.h b/src/modules/main/screen.h index 2e0acbf..e1baef0 100644 --- a/src/modules/main/screen.h +++ b/src/modules/main/screen.h @@ -19,20 +19,22 @@ public: unsigned width() const { return m_resolution.x; } unsigned height() const { return m_resolution.y; } + pixel_t color(uint8_t r, uint8_t g, uint8_t b) const; + void fill(pixel_t color); void draw_pixel(unsigned x, unsigned y, pixel_t color); screen() = delete; +private: struct color_masks { + uint8_t rshift, gshift, bshift; pixel_t r, g, b; color_masks(pixel_t r, pixel_t g, pixel_t b); color_masks(const color_masks &other); }; -private: pixel_t *m_framebuffer; color_masks m_masks; coord m_resolution; }; -