mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
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)
|
m_data(data)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
font::font(const font &other) :
|
||||||
|
m_size(other.m_size),
|
||||||
|
m_count(other.m_count),
|
||||||
|
m_data(other.m_data)
|
||||||
|
{}
|
||||||
|
|
||||||
void
|
void
|
||||||
font::draw_glyph(
|
font::draw_glyph(
|
||||||
screen &s,
|
screen &s,
|
||||||
uint32_t glyph,
|
uint32_t glyph,
|
||||||
screen::pixel_t color,
|
screen::pixel_t fg,
|
||||||
|
screen::pixel_t bg,
|
||||||
unsigned x,
|
unsigned x,
|
||||||
unsigned y) const
|
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());
|
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) {
|
for (int dx = 0; dx < bwidth; ++dx) {
|
||||||
uint8_t byte = data[dy * bwidth + dx];
|
uint8_t byte = data[dy * bwidth + dx];
|
||||||
for (int i = 0; i < 8; ++i) {
|
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);
|
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);
|
s.draw_pixel(x + dx*8 + i, y + dy, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,22 +2,25 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
class font
|
class font
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static font load(void const *data);
|
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 count() const { return m_count; }
|
||||||
unsigned width() const { return m_width; }
|
unsigned width() const { return m_size.x; }
|
||||||
unsigned height() const { return m_height; }
|
unsigned height() const { return m_size.y; }
|
||||||
bool valid() const { return m_count > 0; }
|
bool valid() const { return m_count > 0; }
|
||||||
|
|
||||||
void draw_glyph(
|
void draw_glyph(
|
||||||
screen &s,
|
screen &s,
|
||||||
uint32_t glyph,
|
uint32_t glyph,
|
||||||
screen::pixel_t color,
|
screen::pixel_t fg,
|
||||||
|
screen::pixel_t bg,
|
||||||
unsigned x,
|
unsigned x,
|
||||||
unsigned y) const;
|
unsigned y) const;
|
||||||
|
|
||||||
@@ -25,8 +28,7 @@ private:
|
|||||||
font();
|
font();
|
||||||
font(unsigned height, unsigned width, unsigned count, uint8_t const *data);
|
font(unsigned height, unsigned width, unsigned count, uint8_t const *data);
|
||||||
|
|
||||||
unsigned m_height;
|
coord<unsigned> m_size;
|
||||||
unsigned m_width;
|
|
||||||
unsigned m_count;
|
unsigned m_count;
|
||||||
uint8_t const *m_data;
|
uint8_t const *m_data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "console.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "kernel_data.h"
|
#include "kernel_data.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
@@ -13,22 +14,25 @@ extern "C" {
|
|||||||
void
|
void
|
||||||
kernel_main(popcorn_data *header)
|
kernel_main(popcorn_data *header)
|
||||||
{
|
{
|
||||||
font f = font::load(header->font);
|
console cons{
|
||||||
screen s{
|
font::load(header->font),
|
||||||
|
screen{
|
||||||
header->frame_buffer,
|
header->frame_buffer,
|
||||||
header->hres,
|
header->hres,
|
||||||
header->vres,
|
header->vres,
|
||||||
header->rmask,
|
header->rmask,
|
||||||
header->gmask,
|
header->gmask,
|
||||||
header->bmask};
|
header->bmask},
|
||||||
|
header->log,
|
||||||
|
header->log_length};
|
||||||
|
|
||||||
uint32_t color = header->gmask;
|
const int times = 50;
|
||||||
uint32_t perline = header->hres / f.width();
|
char message[] = " 000 Hello, I am text rendered by the kernel! :-D\n";
|
||||||
const char message[] = "Hello, I am text rendered by the kernel! :-D ";
|
for (int i = 0; i < times; ++i) {
|
||||||
for (int i=0; i<sizeof(message); ++i) {
|
message[1] = '0' + ((i / 100) % 10);
|
||||||
f.draw_glyph(s, message[i], color,
|
message[2] = '0' + ((i / 10) % 10);
|
||||||
(i % perline) * f.width() + 10,
|
message[3] = '0' + (i % 10);
|
||||||
(i / perline) * f.height() + 10);
|
cons.puts(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
do_the_set_registers(header);
|
do_the_set_registers(header);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "screen.h"
|
#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(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(
|
screen::screen(
|
||||||
void *framebuffer,
|
void *framebuffer,
|
||||||
coord_t hres, coord_t vres,
|
unsigned hres, unsigned vres,
|
||||||
pixel_t rmask, pixel_t gmask, pixel_t bmask) :
|
pixel_t rmask, pixel_t gmask, pixel_t bmask) :
|
||||||
m_framebuffer(static_cast<pixel_t *>(framebuffer)),
|
m_framebuffer(static_cast<pixel_t *>(framebuffer)),
|
||||||
m_masks(rmask, gmask, bmask),
|
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
|
void
|
||||||
screen::fill(pixel_t color)
|
screen::fill(pixel_t color)
|
||||||
{
|
{
|
||||||
@@ -22,7 +29,7 @@ screen::fill(pixel_t color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
class screen
|
class screen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using coord_t = uint32_t;
|
|
||||||
using pixel_t = uint32_t;
|
using pixel_t = uint32_t;
|
||||||
|
|
||||||
screen(
|
screen(
|
||||||
void *framebuffer,
|
void *framebuffer,
|
||||||
coord_t hres, coord_t vres,
|
unsigned hres, unsigned vres,
|
||||||
pixel_t rmask, pixel_t gmask, pixel_t bmask);
|
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 fill(pixel_t color);
|
||||||
void draw_pixel(unsigned x, unsigned y, pixel_t color);
|
void draw_pixel(unsigned x, unsigned y, pixel_t color);
|
||||||
|
|
||||||
|
screen() = delete;
|
||||||
|
|
||||||
struct color_masks {
|
struct color_masks {
|
||||||
pixel_t r, g, b;
|
pixel_t r, g, b;
|
||||||
color_masks(pixel_t r, pixel_t g, pixel_t b);
|
color_masks(pixel_t r, pixel_t g, pixel_t b);
|
||||||
};
|
color_masks(const color_masks &other);
|
||||||
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; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pixel_t *m_framebuffer;
|
pixel_t *m_framebuffer;
|
||||||
color_masks m_masks;
|
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