mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 08:24:32 -08:00
Make console support 256 color mode
This commit is contained in:
@@ -1,22 +1,77 @@
|
|||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
|
||||||
|
const char digits[] = "0123456789abcdef";
|
||||||
|
|
||||||
console::console(const font &f, const screen &s, void *scratch, size_t len) :
|
console::console(const font &f, const screen &s, void *scratch, size_t len) :
|
||||||
m_font(f),
|
m_font(f),
|
||||||
m_screen(s),
|
m_screen(s),
|
||||||
m_size(s.width() / f.width(), s.height() / f.height()),
|
m_size(s.width() / f.width(), s.height() / f.height()),
|
||||||
m_fg(0xffffffff),
|
m_fg(0xffffff),
|
||||||
m_bg(0x00000000),
|
m_bg(0),
|
||||||
m_first(0),
|
m_first(0),
|
||||||
m_length(len),
|
m_length(len),
|
||||||
m_data(static_cast<char *>(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 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<char *>(scratch);
|
||||||
for (unsigned i = 0; i < count; ++i)
|
for (unsigned i = 0; i < count; ++i)
|
||||||
m_data[i] = 0;
|
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<screen::pixel_t *>(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<uint16_t *>(m_data + count + palette_size);
|
||||||
|
for (unsigned i = 0; i < count; ++i)
|
||||||
|
m_attrs[i] = m_attr;
|
||||||
|
}
|
||||||
|
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +82,13 @@ console::line_pointer(unsigned line)
|
|||||||
return m_data + ((m_first + line) % m_size.y) * m_size.x;
|
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
|
void
|
||||||
console::repaint()
|
console::repaint()
|
||||||
{
|
{
|
||||||
@@ -35,7 +97,13 @@ console::repaint()
|
|||||||
|
|
||||||
for (unsigned y = 0; y < m_size.y; ++y) {
|
for (unsigned y = 0; y < m_size.y; ++y) {
|
||||||
const char *line = line_pointer(y);
|
const char *line = line_pointer(y);
|
||||||
|
const uint16_t *attrs = attr_pointer(y);
|
||||||
for (unsigned x = 0; x < m_size.x; ++x) {
|
for (unsigned x = 0; x < m_size.x; ++x) {
|
||||||
|
const uint16_t attr = attrs[x];
|
||||||
|
|
||||||
|
set_color(static_cast<uint8_t>(attr),
|
||||||
|
static_cast<uint8_t>(attr >> 8));
|
||||||
|
|
||||||
m_font.draw_glyph(
|
m_font.draw_glyph(
|
||||||
m_screen,
|
m_screen,
|
||||||
line[x] ? line[x] : ' ',
|
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
|
void
|
||||||
console::scroll(unsigned lines)
|
console::scroll(unsigned lines)
|
||||||
{
|
{
|
||||||
@@ -69,11 +147,14 @@ size_t
|
|||||||
console::puts(const char *message)
|
console::puts(const char *message)
|
||||||
{
|
{
|
||||||
char *line = line_pointer(m_pos.y);
|
char *line = line_pointer(m_pos.y);
|
||||||
|
uint16_t *attrs = attr_pointer(m_pos.y);
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
while (message && *message) {
|
while (message && *message) {
|
||||||
const unsigned x = m_pos.x * m_font.width();
|
const unsigned x = m_pos.x * m_font.width();
|
||||||
const unsigned y = m_pos.y * m_font.height();
|
const unsigned y = m_pos.y * m_font.height();
|
||||||
const char c = *message++;
|
const char c = *message++;
|
||||||
|
++count;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\t':
|
case '\t':
|
||||||
@@ -90,7 +171,8 @@ console::puts(const char *message)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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_font.draw_glyph(m_screen, c, m_fg, m_bg, x, y);
|
||||||
m_pos.x++;
|
m_pos.x++;
|
||||||
}
|
}
|
||||||
@@ -105,5 +187,8 @@ console::puts(const char *message)
|
|||||||
line = line_pointer(m_pos.y);
|
line = line_pointer(m_pos.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,22 +14,46 @@ public:
|
|||||||
void repaint();
|
void repaint();
|
||||||
void scroll(unsigned lines);
|
void scroll(unsigned lines);
|
||||||
|
|
||||||
|
void set_color(uint8_t fg, uint8_t bg);
|
||||||
|
|
||||||
size_t puts(const char *message);
|
size_t puts(const char *message);
|
||||||
size_t printf(const char *fmt, ...);
|
size_t printf(const char *fmt, ...);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void put_hex(T x);
|
||||||
|
|
||||||
|
void put_dec(uint32_t x);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char * line_pointer(unsigned line);
|
char * line_pointer(unsigned line);
|
||||||
|
uint16_t * attr_pointer(unsigned line);
|
||||||
|
|
||||||
font m_font;
|
font m_font;
|
||||||
screen m_screen;
|
screen m_screen;
|
||||||
|
|
||||||
coord<unsigned> m_size;
|
coord<unsigned> m_size;
|
||||||
coord<unsigned> m_pos;
|
coord<unsigned> m_pos;
|
||||||
screen::pixel_t m_fg;
|
screen::pixel_t m_fg, m_bg;
|
||||||
screen::pixel_t m_bg;
|
uint16_t m_attr;
|
||||||
|
|
||||||
size_t m_first;
|
size_t m_first;
|
||||||
size_t m_length;
|
size_t m_length;
|
||||||
|
|
||||||
char *m_data;
|
char *m_data;
|
||||||
|
uint16_t *m_attrs;
|
||||||
|
screen::pixel_t *m_palette;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const char digits[];
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void console::put_hex(T x)
|
||||||
|
{
|
||||||
|
static const int chars = sizeof(x) * 2;
|
||||||
|
char message[chars + 1];
|
||||||
|
for (int i=0; i<chars; ++i) {
|
||||||
|
message[chars - i - 1] = digits[(x >> (i*4)) & 0xf];
|
||||||
|
}
|
||||||
|
message[chars] = 0;
|
||||||
|
puts(message);
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ extern "C" {
|
|||||||
void kernel_main(popcorn_data *header);
|
void kernel_main(popcorn_data *header);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
console
|
||||||
kernel_main(popcorn_data *header)
|
load_console(const popcorn_data *header)
|
||||||
{
|
{
|
||||||
console cons{
|
return console{
|
||||||
font::load(header->font),
|
font::load(header->font),
|
||||||
screen{
|
screen{
|
||||||
header->frame_buffer,
|
header->frame_buffer,
|
||||||
@@ -25,10 +25,17 @@ kernel_main(popcorn_data *header)
|
|||||||
header->bmask},
|
header->bmask},
|
||||||
header->log,
|
header->log,
|
||||||
header->log_length};
|
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";
|
char message[] = " 000 Hello, I am text rendered by the kernel! :-D\n";
|
||||||
for (int i = 0; i < times; ++i) {
|
for (int i = 0; i < times; ++i) {
|
||||||
|
cons.set_color(i, 0);
|
||||||
message[1] = '0' + ((i / 100) % 10);
|
message[1] = '0' + ((i / 100) % 10);
|
||||||
message[2] = '0' + ((i / 10) % 10);
|
message[2] = '0' + ((i / 10) % 10);
|
||||||
message[3] = '0' + (i % 10);
|
message[3] = '0' + (i % 10);
|
||||||
|
|||||||
@@ -1,7 +1,40 @@
|
|||||||
#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) {}
|
template <typename T>
|
||||||
screen::color_masks::color_masks(const color_masks &o) : r(o.r), g(o.g), b(o.b) {}
|
static int popcount(T x)
|
||||||
|
{
|
||||||
|
int c = 0;
|
||||||
|
while (x) {
|
||||||
|
c += (x & 1);
|
||||||
|
x = x >> 1;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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<uint8_t>(ctz(r) - (8 - popcount(r)));
|
||||||
|
gshift = static_cast<uint8_t>(ctz(g) - (8 - popcount(g)));
|
||||||
|
bshift = static_cast<uint8_t>(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(
|
screen::screen(
|
||||||
void *framebuffer,
|
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<uint32_t>(r) << m_masks.rshift) & m_masks.r) |
|
||||||
|
((static_cast<uint32_t>(g) << m_masks.gshift) & m_masks.g) |
|
||||||
|
((static_cast<uint32_t>(b) << m_masks.bshift) & m_masks.b);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
screen::fill(pixel_t color)
|
screen::fill(pixel_t color)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,20 +19,22 @@ public:
|
|||||||
unsigned width() const { return m_resolution.x; }
|
unsigned width() const { return m_resolution.x; }
|
||||||
unsigned height() const { return m_resolution.y; }
|
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 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;
|
screen() = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
struct color_masks {
|
struct color_masks {
|
||||||
|
uint8_t rshift, gshift, bshift;
|
||||||
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);
|
color_masks(const color_masks &other);
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
pixel_t *m_framebuffer;
|
pixel_t *m_framebuffer;
|
||||||
color_masks m_masks;
|
color_masks m_masks;
|
||||||
coord<unsigned> m_resolution;
|
coord<unsigned> m_resolution;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user