Implement scrolling console
This commit is contained in:
109
src/modules/main/console.cpp
Normal file
109
src/modules/main/console.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
src/modules/main/console.h
Normal file
35
src/modules/main/console.h
Normal 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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
9
src/modules/main/util.h
Normal 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; }
|
||||
};
|
||||
Reference in New Issue
Block a user