Skip to content

Commit

Permalink
Text Mode enhancement (#1052)
Browse files Browse the repository at this point in the history
add blink support
fill cursor with the foreground color of the character at the cursor's current location
  • Loading branch information
vip-delete committed Jun 24, 2024
1 parent bf20314 commit 21f5b05
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 36 deletions.
30 changes: 19 additions & 11 deletions src/browser/dummy_screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ function DummyScreenAdapter(bus)
is_graphical = false,

// Index 0: ASCII code
// Index 1: Background color
// Index 2: Foreground color
// Index 1: Blinking
// Index 2: Background color
// Index 3: Foreground color
text_mode_data,

// number of columns
Expand All @@ -33,6 +34,12 @@ function DummyScreenAdapter(bus)
// number of rows
text_mode_height;

const CHARACTER_INDEX = 0;
const BLINKING_INDEX = 1;
const BG_COLOR_INDEX = 2;
const FG_COLOR_INDEX = 3;
const TEXT_MODE_COMPONENT_SIZE = 4;

this.bus = bus;

bus.register("screen-set-mode", function(data)
Expand All @@ -51,7 +58,7 @@ function DummyScreenAdapter(bus)
bus.register("screen-put-char", function(data)
{
//console.log(data);
this.put_char(data[0], data[1], data[2], data[3], data[4]);
this.put_char(data[0], data[1], data[2], data[3], data[4], data[5]);
}, this);

bus.register("screen-text-scroll", function(rows)
Expand All @@ -77,15 +84,16 @@ function DummyScreenAdapter(bus)
this.set_size_graphical(data[0], data[1]);
}, this);

this.put_char = function(row, col, chr, bg_color, fg_color)
this.put_char = function(row, col, chr, blinking, bg_color, fg_color)
{
if(row < text_mode_height && col < text_mode_width)
{
var p = 3 * (row * text_mode_width + col);
var p = TEXT_MODE_COMPONENT_SIZE * (row * text_mode_width + col);

text_mode_data[p] = chr;
text_mode_data[p + 1] = bg_color;
text_mode_data[p + 2] = fg_color;
text_mode_data[p + CHARACTER_INDEX] = chr;
text_mode_data[p + BLINKING_INDEX] = blinking;
text_mode_data[p + BG_COLOR_INDEX] = bg_color;
text_mode_data[p + FG_COLOR_INDEX] = fg_color;
}
};

Expand Down Expand Up @@ -113,7 +121,7 @@ function DummyScreenAdapter(bus)
return;
}

text_mode_data = new Int32Array(cols * rows * 3);
text_mode_data = new Int32Array(cols * rows * TEXT_MODE_COMPONENT_SIZE);

text_mode_width = cols;
text_mode_height = rows;
Expand Down Expand Up @@ -168,11 +176,11 @@ function DummyScreenAdapter(bus)
this.get_text_row = function(i)
{
var row = "";
var offset = 3 * i * text_mode_width;
var offset = TEXT_MODE_COMPONENT_SIZE * i * text_mode_width;

for(var j = 0; j < text_mode_width; j++)
{
row += String.fromCharCode(text_mode_data[offset + 3 * j]);
row += String.fromCharCode(text_mode_data[offset + CHARACTER_INDEX + TEXT_MODE_COMPONENT_SIZE * j]);
}

return row;
Expand Down
64 changes: 43 additions & 21 deletions src/browser/screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ function ScreenAdapter(screen_container, bus)
is_graphical = false,

// Index 0: ASCII code
// Index 1: Background color
// Index 2: Foreground color
// Index 1: Blinking
// Index 2: Background color
// Index 3: Foreground color
text_mode_data,

// number of columns
Expand All @@ -48,6 +49,12 @@ function ScreenAdapter(screen_container, bus)
// number of rows
text_mode_height;

const CHARACTER_INDEX = 0;
const BLINKING_INDEX = 1;
const BG_COLOR_INDEX = 2;
const FG_COLOR_INDEX = 3;
const TEXT_MODE_COMPONENT_SIZE = 4;

var stopped = false;

var screen = this;
Expand Down Expand Up @@ -115,6 +122,7 @@ function ScreenAdapter(screen_container, bus)

graphic_context.imageSmoothingEnabled = false;

cursor_element.classList.add("cursor");
cursor_element.style.position = "absolute";
cursor_element.style.backgroundColor = "#ccc";
cursor_element.style.width = "7px";
Expand All @@ -138,7 +146,7 @@ function ScreenAdapter(screen_container, bus)
bus.register("screen-put-char", function(data)
{
//console.log(data);
this.put_char(data[0], data[1], data[2], data[3], data[4]);
this.put_char(data[0], data[1], data[2], data[3], data[4], data[5]);
}, this);

bus.register("screen-update-cursor", function(data)
Expand Down Expand Up @@ -199,11 +207,15 @@ function ScreenAdapter(screen_container, bus)
{
for(let y = 0; y < text_mode_height; y++)
{
const index = (y * text_mode_width + x) * 3;
context.fillStyle = number_as_color(text_mode_data[index + 1]);
const index = (y * text_mode_width + x) * TEXT_MODE_COMPONENT_SIZE;
const character = text_mode_data[index + CHARACTER_INDEX];
const bg_color = text_mode_data[index + BG_COLOR_INDEX];
const fg_color = text_mode_data[index + FG_COLOR_INDEX];

context.fillStyle = number_as_color(bg_color);
context.fillRect(x * char_size[0], y * char_size[1], char_size[0], char_size[1]);
context.fillStyle = number_as_color(text_mode_data[index + 2]);
context.fillText(charmap[text_mode_data[index]], x * char_size[0], y * char_size[1]);
context.fillStyle = number_as_color(fg_color);
context.fillText(charmap[character], x * char_size[0], y * char_size[1]);
}
}

Expand All @@ -223,16 +235,17 @@ function ScreenAdapter(screen_container, bus)
return image;
};

this.put_char = function(row, col, chr, bg_color, fg_color)
this.put_char = function(row, col, chr, blinking, bg_color, fg_color)
{
if(row < text_mode_height && col < text_mode_width)
{
var p = 3 * (row * text_mode_width + col);
var p = TEXT_MODE_COMPONENT_SIZE * (row * text_mode_width + col);

dbg_assert(chr >= 0 && chr < 0x100);
text_mode_data[p] = chr;
text_mode_data[p + 1] = bg_color;
text_mode_data[p + 2] = fg_color;
text_mode_data[p + CHARACTER_INDEX] = chr;
text_mode_data[p + BLINKING_INDEX] = blinking;
text_mode_data[p + BG_COLOR_INDEX] = bg_color;
text_mode_data[p + FG_COLOR_INDEX] = fg_color;

changed_rows[row] = 1;
}
Expand Down Expand Up @@ -305,7 +318,7 @@ function ScreenAdapter(screen_container, bus)
}

changed_rows = new Int8Array(rows);
text_mode_data = new Int32Array(cols * rows * 3);
text_mode_data = new Int32Array(cols * rows * TEXT_MODE_COMPONENT_SIZE);

text_mode_width = cols;
text_mode_height = rows;
Expand Down Expand Up @@ -468,12 +481,13 @@ function ScreenAdapter(screen_container, bus)

this.text_update_row = function(row)
{
var offset = 3 * row * text_mode_width,
var offset = TEXT_MODE_COMPONENT_SIZE * row * text_mode_width,
row_element,
color_element,
fragment;

var bg_color,
var blinking,
bg_color,
fg_color,
text;

Expand All @@ -484,8 +498,14 @@ function ScreenAdapter(screen_container, bus)
{
color_element = document.createElement("span");

bg_color = text_mode_data[offset + 1];
fg_color = text_mode_data[offset + 2];
blinking = text_mode_data[offset + BLINKING_INDEX];
bg_color = text_mode_data[offset + BG_COLOR_INDEX];
fg_color = text_mode_data[offset + FG_COLOR_INDEX];

if(blinking)
{
color_element.classList.add("blink");
}

color_element.style.backgroundColor = number_as_color(bg_color);
color_element.style.color = number_as_color(fg_color);
Expand All @@ -494,16 +514,17 @@ function ScreenAdapter(screen_container, bus)

// put characters of the same color in one element
while(i < text_mode_width &&
text_mode_data[offset + 1] === bg_color &&
text_mode_data[offset + 2] === fg_color)
text_mode_data[offset + BLINKING_INDEX] === blinking &&
text_mode_data[offset + BG_COLOR_INDEX] === bg_color &&
text_mode_data[offset + FG_COLOR_INDEX] === fg_color)
{
var ascii = text_mode_data[offset];
var ascii = text_mode_data[offset + CHARACTER_INDEX];

text += charmap[ascii];
dbg_assert(charmap[ascii]);

i++;
offset += 3;
offset += TEXT_MODE_COMPONENT_SIZE;

if(row === cursor_row)
{
Expand All @@ -516,6 +537,7 @@ function ScreenAdapter(screen_container, bus)
else if(i === cursor_col + 1)
{
// found the cursor
cursor_element.style.backgroundColor = color_element.style.color;
fragment.appendChild(cursor_element);
break;
}
Expand Down
15 changes: 11 additions & 4 deletions src/vga.js
Original file line number Diff line number Diff line change
Expand Up @@ -854,10 +854,13 @@ VGAScreen.prototype.text_mode_redraw = function()
{
var addr = this.start_address << 1,
chr,
blinking,
color;

const split_screen_row = this.scan_line_to_screen_row(this.line_compare);
const row_offset = Math.max(0, (this.offset_register * 2 - this.max_cols) * 2);
const blink_flag = this.attribute_mode & 1 << 3;
const bg_color_mask = blink_flag ? 7 : 0xF;

for(var row = 0; row < this.max_rows; row++)
{
Expand All @@ -870,9 +873,10 @@ VGAScreen.prototype.text_mode_redraw = function()
{
chr = this.vga_memory[addr];
color = this.vga_memory[addr | 1];
blinking = blink_flag && (color & 1 << 7);

this.bus.send("screen-put-char", [row, col, chr,
this.vga256_palette[this.dac_mask & this.dac_map[color >> 4 & 0xF]],
this.bus.send("screen-put-char", [row, col, chr, blinking,
this.vga256_palette[this.dac_mask & this.dac_map[color >> 4 & bg_color_mask]],
this.vga256_palette[this.dac_mask & this.dac_map[color & 0xF]]]);

addr += 2;
Expand Down Expand Up @@ -924,9 +928,12 @@ VGAScreen.prototype.vga_memory_write_text_mode = function(addr, value)
chr = value;
color = this.vga_memory[addr | 1];
}
const blink_flag = this.attribute_mode & 1 << 3;
const blinking = blink_flag && (color & 1 << 7);
const bg_color_mask = blink_flag ? 7 : 0xF;

this.bus.send("screen-put-char", [row, col, chr,
this.vga256_palette[this.dac_mask & this.dac_map[color >> 4 & 0xF]],
this.bus.send("screen-put-char", [row, col, chr, blinking,
this.vga256_palette[this.dac_mask & this.dac_map[color >> 4 & bg_color_mask]],
this.vga256_palette[this.dac_mask & this.dac_map[color & 0xF]]]);
};

Expand Down
16 changes: 16 additions & 0 deletions v86.css
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,22 @@ h4 {
#terminal {
max-width: 1024px;
}
.blink {
animation: blink 0.6s step-start infinite;
}
@keyframes blink {
50% {
color: transparent;
}
}
.cursor {
animation: cursor 0.6s step-start infinite;
}
@keyframes cursor {
50% {
background-color: transparent;
}
}

/* the code below was copied from xterm.css */

Expand Down

0 comments on commit 21f5b05

Please sign in to comment.