Implement scrolling console

This commit is contained in:
Justin C. Miller
2018-04-10 02:15:41 -07:00
parent 067ff3af89
commit 2d52f64eb6
8 changed files with 217 additions and 45 deletions

View File

@@ -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<char *>(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);
}
}
}

View File

@@ -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<unsigned> m_size;
coord<unsigned> m_pos;
screen::pixel_t m_fg;
screen::pixel_t m_bg;
size_t m_first;
size_t m_length;
char *m_data;
};

View File

@@ -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);
}
}

View File

@@ -2,22 +2,25 @@
#include <stdint.h>
#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<unsigned> m_size;
unsigned m_count;
uint8_t const *m_data;
};

View File

@@ -1,6 +1,7 @@
#include <stddef.h>
#include <stdint.h>
#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{
console cons{
font::load(header->font),
screen{
header->frame_buffer,
header->hres,
header->vres,
header->rmask,
header->gmask,
header->bmask};
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<sizeof(message); ++i) {
f.draw_glyph(s, message[i], color,
(i % perline) * f.width() + 10,
(i / perline) * f.height() + 10);
const int times = 50;
char message[] = " 000 Hello, I am text rendered by the kernel! :-D\n";
for (int i = 0; i < times; ++i) {
message[1] = '0' + ((i / 100) % 10);
message[2] = '0' + ((i / 10) % 10);
message[3] = '0' + (i % 10);
cons.puts(message);
}
do_the_set_registers(header);

View File

@@ -1,11 +1,11 @@
#include "screen.h"
screen::color_masks::color_masks(pixel_t r, pixel_t g, pixel_t b) : r(r), g(g), b(b) {}
screen::resolution::resolution(coord_t w, coord_t h) : w(w), h(h) {}
screen::color_masks::color_masks(const color_masks &o) : r(o.r), g(o.g), b(o.b) {}
screen::screen(
void *framebuffer,
coord_t hres, coord_t vres,
unsigned hres, unsigned vres,
pixel_t rmask, pixel_t gmask, pixel_t bmask) :
m_framebuffer(static_cast<pixel_t *>(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;
}

View File

@@ -2,38 +2,37 @@
#include <stddef.h>
#include <stdint.h>
#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);
screen() = delete;
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; }
color_masks(const color_masks &other);
};
private:
pixel_t *m_framebuffer;
color_masks m_masks;
resolution m_resolution;
coord<unsigned> m_resolution;
};

9
src/modules/main/util.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
template <typename T>
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; }
};