diff --git a/src/modules/main/console.cpp b/src/modules/main/console.cpp new file mode 100644 index 0000000..927f9ec --- /dev/null +++ b/src/modules/main/console.cpp @@ -0,0 +1,109 @@ +#include "console.h" + +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_first(0), + m_length(len), + m_data(static_cast(scratch)) +{ + if (len < m_size.size()) { + m_data = nullptr; + } + + const unsigned count = m_size.size(); + for (unsigned i = 0; i < count; ++i) + m_data[i] = 0; + repaint(); +} + +char * +console::line_pointer(unsigned line) +{ + if (!m_data) return nullptr; + return m_data + ((m_first + line) % m_size.y) * m_size.x; +} + +void +console::repaint() +{ + m_screen.fill(m_bg); + if (!m_data) return; + + for (unsigned y = 0; y < m_size.y; ++y) { + const char *line = line_pointer(y); + for (unsigned x = 0; x < m_size.x; ++x) { + m_font.draw_glyph( + m_screen, + line[x] ? line[x] : ' ', + m_fg, + m_bg, + x * m_font.width(), + y * m_font.height()); + } + } +} + +void +console::scroll(unsigned lines) +{ + if (!m_data) { + m_pos.x = 0; + m_pos.y = 0; + } else { + unsigned bytes = lines * m_size.x; + char *line = line_pointer(0); + for (unsigned i = 0; i < bytes; ++i) + *line++ = 0; + + m_first = (m_first + lines) % m_size.y; + m_pos.y -= lines; + } + repaint(); +} + +size_t +console::puts(const char *message) +{ + char *line = line_pointer(m_pos.y); + + 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++; + + switch (c) { + case '\t': + m_pos.x = (m_pos.x + 4) / 4 * 4; + break; + + case '\r': + m_pos.x = 0; + break; + + case '\n': + m_pos.x = 0; + m_pos.y++; + break; + + default: + if (m_data) line[m_pos.x] = c; + m_font.draw_glyph(m_screen, c, m_fg, m_bg, x, y); + m_pos.x++; + } + + if (m_pos.x >= m_size.x) { + m_pos.x = m_pos.x % m_size.x; + m_pos.y++; + } + + if (m_pos.y >= m_size.y) { + scroll(1); + line = line_pointer(m_pos.y); + } + } +} + diff --git a/src/modules/main/console.h b/src/modules/main/console.h new file mode 100644 index 0000000..60b2d3f --- /dev/null +++ b/src/modules/main/console.h @@ -0,0 +1,35 @@ +#pragma once + +#include "font.h" +#include "screen.h" +#include "util.h" + +struct console_data; + +class console +{ +public: + console(const font &f, const screen &s, void *scratch, size_t len); + + void repaint(); + void scroll(unsigned lines); + + size_t puts(const char *message); + size_t printf(const char *fmt, ...); + +private: + char * line_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; + + size_t m_first; + size_t m_length; + + char *m_data; +}; diff --git a/src/modules/main/font.cpp b/src/modules/main/font.cpp index fe24501..69f2bcd 100644 --- a/src/modules/main/font.cpp +++ b/src/modules/main/font.cpp @@ -55,24 +55,31 @@ font::font(unsigned height, unsigned width, unsigned count, uint8_t const *data) m_data(data) {} +font::font(const font &other) : + m_size(other.m_size), + m_count(other.m_count), + m_data(other.m_data) +{} + void font::draw_glyph( screen &s, uint32_t glyph, - screen::pixel_t color, + screen::pixel_t fg, + screen::pixel_t bg, unsigned x, unsigned y) const { - unsigned bwidth = (m_width+7)/8; + unsigned bwidth = (m_size.x+7)/8; uint8_t const *data = m_data + (glyph * glyph_bytes()); - for (int dy = 0; dy < m_height; ++dy) { + for (int dy = 0; dy < m_size.y; ++dy) { for (int dx = 0; dx < bwidth; ++dx) { uint8_t byte = data[dy * bwidth + dx]; for (int i = 0; i < 8; ++i) { - if (dx*8 + i >= m_width) continue; + if (dx*8 + i >= m_size.x) continue; const uint8_t mask = 1 << (7-i); - uint32_t c = (byte & mask) ? color : 0; + uint32_t c = (byte & mask) ? fg : bg; s.draw_pixel(x + dx*8 + i, y + dy, c); } } diff --git a/src/modules/main/font.h b/src/modules/main/font.h index 4447d1c..1299dca 100644 --- a/src/modules/main/font.h +++ b/src/modules/main/font.h @@ -2,22 +2,25 @@ #include #include "screen.h" +#include "util.h" class font { public: static font load(void const *data); + font(const font &other); - unsigned glyph_bytes() const { return m_height * ((m_width + 7) / 8); } + unsigned glyph_bytes() const { return m_size.y * ((m_size.x + 7) / 8); } unsigned count() const { return m_count; } - unsigned width() const { return m_width; } - unsigned height() const { return m_height; } + unsigned width() const { return m_size.x; } + unsigned height() const { return m_size.y; } bool valid() const { return m_count > 0; } void draw_glyph( screen &s, uint32_t glyph, - screen::pixel_t color, + screen::pixel_t fg, + screen::pixel_t bg, unsigned x, unsigned y) const; @@ -25,8 +28,7 @@ private: font(); font(unsigned height, unsigned width, unsigned count, uint8_t const *data); - unsigned m_height; - unsigned m_width; + coord m_size; unsigned m_count; uint8_t const *m_data; }; diff --git a/src/modules/main/main.cpp b/src/modules/main/main.cpp index cccd8d8..d25f2d8 100644 --- a/src/modules/main/main.cpp +++ b/src/modules/main/main.cpp @@ -1,6 +1,7 @@ #include #include +#include "console.h" #include "font.h" #include "kernel_data.h" #include "screen.h" @@ -13,22 +14,25 @@ extern "C" { void kernel_main(popcorn_data *header) { - font f = font::load(header->font); - screen s{ - header->frame_buffer, - header->hres, - header->vres, - header->rmask, - header->gmask, - header->bmask}; + console cons{ + font::load(header->font), + screen{ + header->frame_buffer, + header->hres, + header->vres, + header->rmask, + header->gmask, + header->bmask}, + header->log, + header->log_length}; - uint32_t color = header->gmask; - uint32_t perline = header->hres / f.width(); - const char message[] = "Hello, I am text rendered by the kernel! :-D "; - for (int i=0; i(framebuffer)), m_masks(rmask, gmask, bmask), @@ -13,6 +13,13 @@ screen::screen( { } +screen::screen(const screen &other) : + m_framebuffer(other.m_framebuffer), + m_masks(other.m_masks), + m_resolution(other.m_resolution) +{ +} + void screen::fill(pixel_t color) { @@ -22,7 +29,7 @@ screen::fill(pixel_t color) } void -screen::draw_pixel(coord_t x, coord_t y, pixel_t color) +screen::draw_pixel(unsigned x, unsigned y, pixel_t color) { - m_framebuffer[x + y * m_resolution.w] = color; + m_framebuffer[x + y * m_resolution.x] = color; } diff --git a/src/modules/main/screen.h b/src/modules/main/screen.h index 6284546..2e0acbf 100644 --- a/src/modules/main/screen.h +++ b/src/modules/main/screen.h @@ -2,38 +2,37 @@ #include #include +#include "util.h" + class screen { public: - using coord_t = uint32_t; using pixel_t = uint32_t; screen( void *framebuffer, - coord_t hres, coord_t vres, + unsigned hres, unsigned vres, pixel_t rmask, pixel_t gmask, pixel_t bmask); + screen(const screen &other); + unsigned width() const { return m_resolution.x; } + unsigned height() const { return m_resolution.y; } void fill(pixel_t color); void draw_pixel(unsigned x, unsigned y, pixel_t color); - struct color_masks { - pixel_t r, g, b; - color_masks(pixel_t r, pixel_t g, pixel_t b); - }; screen() = delete; - screen(const screen &) = delete; - struct resolution { - coord_t w, h; - resolution(coord_t w, coord_t h); - coord_t size() const { return w * h; } - }; + struct color_masks { + 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; - resolution m_resolution; + pixel_t *m_framebuffer; + color_masks m_masks; + coord m_resolution; }; diff --git a/src/modules/main/util.h b/src/modules/main/util.h new file mode 100644 index 0000000..6cf2c32 --- /dev/null +++ b/src/modules/main/util.h @@ -0,0 +1,9 @@ +#pragma once + +template +struct coord { + T x, y; + coord() : x(T{}), y(T{}) {} + coord(T x, T y) : x(x), y(y) {} + T size() const { return x * y; } +};