/
dgrigorev
/
MicroNT
Обзор
Документация
Войти
/
dgrigorev
/
MicroNT
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
kernel/hal/x64/vga.cpp
1 191 строка
61 KB
Дмитрий Григорьев
Add PS2 mouse driver
19 май 2026, 14:05
19 май 2026, 14:05
ae25429
Код
Авторство
О чём код?
// vga.cpp -- GOP framebuffer text console (replaces legacy VGA MMIO). // Renders text directly into the UEFI GOP linear framebuffer. // No CRTC registers, no 0xB8000 -- bypasses all VGA text-mode quirks. #include "../../include/ntdef.h" #include "../../include/bootinfo.h" #include "../../include/hal.h" namespace VGA { static const u8 s_font[4096] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0xC4, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x32, 0x30, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; // --------------------------------------------------------------------------- // Framebuffer state (set once from BootInfo by SetFramebuffer()) // --------------------------------------------------------------------------- static u32* s_fb = nullptr; static u32 s_fb_w = 0; // pixels wide static u32 s_fb_h = 0; // pixels tall static u32 s_fb_stride = 0; // pixels per scan line static bool s_fb_bgr = false;// true = BGRX, false = RGBX // Text-mode cursor (character units) static u32 s_cols = 80; static u32 s_rows = 25; static u32 s_row = 1; static u32 s_col = 0; static bool s_cursor_visible = false; // is cursor currently drawn? static bool s_mouse_visible = false; static u32 s_mouse_x = 0; static u32 s_mouse_y = 0; static u32 s_mouse_backing[24 * 32]; static u32 s_origin_x = 0; // pixel origin of the text surface static u32 s_origin_y = 0; static constexpr u32 CHAR_W = 8; static constexpr u32 CHAR_H = 16; // --------------------------------------------------------------------------- // CGA 16-colour palette // --------------------------------------------------------------------------- static const u32 s_palette[16] = { 0x000000, 0x0000AA, 0x00AA00, 0x00AAAA, 0xAA0000, 0xAA00AA, 0xAA5500, 0xAAAAAA, 0x555555, 0x5555FF, 0x55FF55, 0x55FFFF, 0xFF5555, 0xFF55FF, 0xFFFF55, 0xFFFFFF, }; // Convert RGB value to native pixel word (RGBX or BGRX) static u32 ToPixel(u32 rgb) { u8 r = (u8)(rgb >> 16), g = (u8)(rgb >> 8), b = (u8)(rgb); if (s_fb_bgr) return (u32)b | ((u32)g << 8) | ((u32)r << 16); return (u32)r | ((u32)g << 8) | ((u32)b << 16); } static u32 AttrFg(u8 attr) { return ToPixel(s_palette[attr & 0x0F]); } static u32 AttrBg(u8 attr) { return ToPixel(s_palette[(attr >> 4) & 0x07]); } static void EraseCursor(); static void DrawCursorShape(); static void FillRect(u32 x, u32 y, u32 w, u32 h, u32 rgb) { if (!s_fb || x >= s_fb_w || y >= s_fb_h) return; if (x + w > s_fb_w) w = s_fb_w - x; if (y + h > s_fb_h) h = s_fb_h - y; u32 px = ToPixel(rgb); for (u32 yy = 0; yy < h; ++yy) { u32* row = s_fb + (y + yy) * s_fb_stride + x; for (u32 xx = 0; xx < w; ++xx) row[xx] = px; } } static void RectOutline(u32 x, u32 y, u32 w, u32 h, u32 light, u32 dark) { if (w < 2 || h < 2) return; FillRect(x, y, w, 1, light); FillRect(x, y, 1, h, light); FillRect(x, y + h - 1, w, 1, dark); FillRect(x + w - 1, y, 1, h, dark); } static void FillVerticalGradient(u32 x, u32 y, u32 w, u32 h, u32 top, u32 bottom) { if (h == 0) return; int tr = (top >> 16) & 0xFF, tg = (top >> 8) & 0xFF, tb = top & 0xFF; int br = (bottom >> 16) & 0xFF, bg = (bottom >> 8) & 0xFF, bb = bottom & 0xFF; for (u32 yy = 0; yy < h; ++yy) { u32 r = (u32)(tr + ((br - tr) * (int)yy) / (int)h); u32 g = (u32)(tg + ((bg - tg) * (int)yy) / (int)h); u32 b = (u32)(tb + ((bb - tb) * (int)yy) / (int)h); FillRect(x, y + yy, w, 1, (r << 16) | (g << 8) | b); } } static void DrawGlyphAbs(u32 px, u32 py, u8 ch, u32 fg, u32 bg) { if (!s_fb) return; const u8* g = &s_font[(u32)ch * 16]; for (u32 r = 0; r < CHAR_H; ++r) { if (py + r >= s_fb_h) break; u32* line = s_fb + (py + r) * s_fb_stride + px; u8 bits = g[r]; for (u32 c = 0; c < CHAR_W; ++c) { if (px + c < s_fb_w) line[c] = (bits & (0x80u >> c)) ? fg : bg; } } } static void DrawTextAbs(u32 x, u32 y, const char* s, u32 fg, u32 bg) { for (u32 i = 0; s[i]; ++i) DrawGlyphAbs(x + i * CHAR_W, y, (u8)s[i], ToPixel(fg), ToPixel(bg)); } static void FillEllipse(u32 cx, u32 cy, u32 rx, u32 ry, u32 rgb) { if (!s_fb || rx == 0 || ry == 0) return; u32 px = ToPixel(rgb); u32 x0 = cx > rx ? cx - rx : 0; u32 y0 = cy > ry ? cy - ry : 0; u32 x1 = cx + rx < s_fb_w ? cx + rx : s_fb_w - 1; u32 y1 = cy + ry < s_fb_h ? cy + ry : s_fb_h - 1; u64 rr = (u64)rx * rx * ry * ry; for (u32 y = y0; y <= y1; ++y) { i64 dy = (i64)y - (i64)cy; for (u32 x = x0; x <= x1; ++x) { i64 dx = (i64)x - (i64)cx; u64 v = (u64)(dx * dx) * ry * ry + (u64)(dy * dy) * rx * rx; if (v <= rr) s_fb[y * s_fb_stride + x] = px; } } } static void DrawFlag(u32 x, u32 y, u32 scale) { u32 s = scale ? scale : 1; FillVerticalGradient(x, y, 11 * s, 11 * s, 0xFF744E, 0xE41D19); FillVerticalGradient(x + 13 * s, y, 11 * s, 11 * s, 0x8BF168, 0x15A333); FillVerticalGradient(x, y + 13 * s, 11 * s, 11 * s, 0x68D5FF, 0x116CE4); FillVerticalGradient(x + 13 * s, y + 13 * s, 11 * s, 11 * s, 0xFFEC72, 0xEDA610); } static void DrawDesktopIcon(u32 x, u32 y, const char* label, u32 body, u32 shade) { FillVerticalGradient(x + 17, y + 7, 42, 42, 0xFFFFFF, body); FillRect(x + 23, y + 13, 30, 21, shade); RectOutline(x + 17, y + 7, 42, 42, 0xFFFFFF, 0x375E9B); FillRect(x + 4, y + 56, 72, 16, 0x247DD8); DrawTextAbs(x + 7, y + 56, label, 0xFFFFFF, 0x247DD8); } static void DrawFolderIcon(u32 x, u32 y, const char* label) { FillRect(x + 18, y + 15, 38, 30, 0xFFC229); FillRect(x + 22, y + 8, 20, 9, 0xFFE27A); RectOutline(x + 18, y + 15, 38, 30, 0xFFF2A2, 0xDC8611); FillRect(x + 4, y + 56, 72, 16, 0x247DD8); DrawTextAbs(x + 7, y + 56, label, 0xFFFFFF, 0x247DD8); } static void DrawPanelWindow(u32 x, u32 y, u32 w, u32 h, const char* title, bool toolbar, const char* status) { FillRect(x + 8, y + 12, w, h, 0x174A86); FillRect(x, y, w, h, 0xF8FCFF); RectOutline(x, y, w, h, 0xFFFFFF, 0x2375D5); FillVerticalGradient(x + 1, y + 1, w - 2, 30, 0x4CB4FF, 0x0960C5); FillVerticalGradient(x + 8, y + 8, 15, 15, 0xFFFFFF, 0x0B5DBC); DrawTextAbs(x + 30, y + 8, title, 0xFFFFFF, 0x197DE5); u32 bx = x + w - 76; for (u32 i = 0; i < 3; ++i) { u32 c1 = i == 2 ? 0xFF927A : 0x72C6FF; u32 c2 = i == 2 ? 0xE02618 : 0x1979E2; FillVerticalGradient(bx + i * 24, y + 6, 20, 20, c1, c2); RectOutline(bx + i * 24, y + 6, 20, 20, 0xC7DEFF, 0x0D2D89); } DrawTextAbs(bx + 6, y + 7, "_", 0xFFFFFF, 0x1979E2); DrawTextAbs(bx + 30, y + 7, "o", 0xFFFFFF, 0x1979E2); DrawTextAbs(bx + 54, y + 7, "x", 0xFFFFFF, 0xE02618); u32 cy = y + 31; if (toolbar) { FillVerticalGradient(x + 1, cy, w - 2, 38, 0xFFFFFF, 0xEEF6FF); FillRect(x + 1, cy + 37, w - 2, 1, 0xC8D9EF); DrawTextAbs(x + 12, cy + 11, "< Back", 0x28445F, 0xF8FCFF); FillRect(x + w - 250, cy + 7, 145, 24, 0xFFFFFF); RectOutline(x + w - 250, cy + 7, 145, 24, 0xB9CBE0, 0xB9CBE0); DrawTextAbs(x + w - 238, cy + 11, title, 0x39627F, 0xFFFFFF); FillRect(x + w - 96, cy + 7, 84, 24, 0xFFFFFF); RectOutline(x + w - 96, cy + 7, 84, 24, 0xB9CBE0, 0xB9CBE0); DrawTextAbs(x + w - 86, cy + 11, "Search", 0x7C8DA0, 0xFFFFFF); cy += 38; } FillVerticalGradient(x + 12, cy + 12, 150, h - (cy - y) - 46, 0xE7F3FF, 0xD3E8FF); RectOutline(x + 12, cy + 12, 150, h - (cy - y) - 46, 0xFFFFFF, 0xC3D8EF); DrawTextAbs(x + 24, cy + 24, "System Tasks", 0x153F77, 0xE7F3FF); DrawTextAbs(x + 24, cy + 52, "View information", 0x244E7C, 0xE2EFFF); DrawTextAbs(x + 24, cy + 78, "Change settings", 0x244E7C, 0xDFEDFF); DrawTextAbs(x + 24, cy + 120, "Other Places", 0x153F77, 0xDCEBFF); u32 px = x + 184; DrawTextAbs(px, cy + 18, "Hard Disk Drives", 0x084FB4, 0xF8FCFF); for (u32 i = 0; i < 4; ++i) { u32 ix = px + (i % 2) * 190; u32 iy = cy + 52 + (i / 2) * 72; FillVerticalGradient(ix, iy + 8, 40, 25, 0xFFFFFF, 0x65788D); RectOutline(ix, iy + 8, 40, 25, 0xFFFFFF, 0x65788D); DrawTextAbs(ix + 52, iy, i == 0 ? "System (C:)" : (i == 1 ? "Data (D:)" : (i == 2 ? "DVD (E:)" : "USB (F:)")), 0x203B55, 0xF8FCFF); FillRect(ix + 52, iy + 22, 100, 8, 0xEEF4FB); FillVerticalGradient(ix + 53, iy + 23, 58 + i * 8, 6, 0x0A61D5, 0x4AA8FF); } FillVerticalGradient(x + 1, y + h - 24, w - 2, 23, 0xF5FBFF, 0xD9ECFF); DrawTextAbs(x + 10, y + h - 18, status, 0x526A82, 0xE5F3FF); } static void DrawMouseCursor(u32 x, u32 y) { static const char* rows[] = { "X...........", "XX..........", "XOX.........", "XOOX........", "XOOOX.......", "XOOOOX......", "XOOOOOX.....", "XOOOOOOX....", "XOOOOOOOX...", "XOOOOXXXX...", "XOOXOX......", "XOX..OX.....", "XX...OX.....", "X.....OX....", "......OX....", ".......X....", }; for (u32 r = 0; r < 16; ++r) { for (u32 c = 0; c < 12; ++c) { char p = rows[r][c]; if (p == '.') continue; FillRect(x + c * 2, y + r * 2, 2, 2, p == 'X' ? 0x000000 : 0xFFFFFF); } } } static void RestoreMouseCursor() { if (!s_fb || !s_mouse_visible) return; for (u32 y = 0; y < 32; ++y) { if (s_mouse_y + y >= s_fb_h) break; for (u32 x = 0; x < 24; ++x) { if (s_mouse_x + x >= s_fb_w) break; s_fb[(s_mouse_y + y) * s_fb_stride + (s_mouse_x + x)] = s_mouse_backing[y * 24 + x]; } } s_mouse_visible = false; } static void SaveMouseCursor(u32 x0, u32 y0) { if (!s_fb) return; for (u32 y = 0; y < 32; ++y) { for (u32 x = 0; x < 24; ++x) { if (x0 + x < s_fb_w && y0 + y < s_fb_h) { s_mouse_backing[y * 24 + x] = s_fb[(y0 + y) * s_fb_stride + (x0 + x)]; } else { s_mouse_backing[y * 24 + x] = 0; } } } } // --------------------------------------------------------------------------- // Draw one character at text cell (cx, cy) with given foreground/background // --------------------------------------------------------------------------- static void DrawChar(u32 cx, u32 cy, u8 ch, u32 fg, u32 bg) { if (!s_fb || cx >= s_cols || cy >= s_rows) return; u32 px = s_origin_x + cx * CHAR_W, py = s_origin_y + cy * CHAR_H; const u8* g = &s_font[(u32)ch * 16]; for (u32 r = 0; r < CHAR_H; ++r) { if (py + r >= s_fb_h) break; u32* line = s_fb + (py + r) * s_fb_stride + px; u8 bits = g[r]; for (u32 c = 0; c < CHAR_W; ++c) { if (px + c < s_fb_w) line[c] = (bits & (0x80u >> c)) ? fg : bg; } } } // --------------------------------------------------------------------------- // Software text buffer so we can scroll and redraw // --------------------------------------------------------------------------- struct Cell { u8 ch, attr; }; static Cell s_cells[64][256]; // supports up to 256 cols x 64 rows (e.g. 2048x1024 at 8x16) static void RedrawAll() { for (u32 r = 0; r < s_rows; ++r) for (u32 c = 0; c < s_cols; ++c) { Cell& cell = s_cells[r][c]; DrawChar(c, r, cell.ch, AttrFg(cell.attr), AttrBg(cell.attr)); } } static void SetCell(u32 r, u32 c, u8 ch, u8 attr) { if (r >= s_rows || c >= s_cols) return; s_cells[r][c] = { ch, attr }; DrawChar(c, r, ch, AttrFg(attr), AttrBg(attr)); } static void Scroll() { // Row 0 = header, row s_rows-1 = status bar -- scroll only rows 1..(s_rows-2) u32 last = s_rows > 2 ? s_rows - 2 : 1; for (u32 r = 2; r <= last; ++r) for (u32 c = 0; c < s_cols; ++c) s_cells[r-1][c] = s_cells[r][c]; for (u32 c = 0; c < s_cols; ++c) s_cells[last][c] = { ' ', 0x07 }; RedrawAll(); s_row = last; } void PutChar(char ch, u8 attr) { EraseCursor(); // Clamp s_row: row 0 = header, last row = status bar u32 max_row = s_rows > 1 ? s_rows - 2 : 1; if (ch == '\b') { if (s_col > 0) { --s_col; SetCell(s_row, s_col, ' ', 0x07); } DrawCursorShape(); return; } if (ch == '\r') { s_col = 0; DrawCursorShape(); return; } if (ch == '\n') { s_col = 0; if (++s_row > max_row) Scroll(); DrawCursorShape(); return; } SetCell(s_row, s_col, ch, attr); if (++s_col >= s_cols) { s_col = 0; if (++s_row > max_row) Scroll(); } DrawCursorShape(); } // Update hardware text cursor (no-op for GOP mode; kept for ABI compat) static void EraseCursor() { if (!s_cursor_visible || !s_fb) return; // Redraw the character underneath to remove the cursor bar if (s_row < s_rows && s_col < s_cols) { Cell& cell = s_cells[s_row][s_col]; DrawChar(s_col, s_row, cell.ch, AttrFg(cell.attr), AttrBg(cell.attr)); } s_cursor_visible = false; } static void DrawCursorShape() { if (!s_fb || s_row >= s_rows || s_col >= s_cols) return; // Underline cursor: last 2 pixel rows of the character cell u32 px = s_origin_x + s_col * CHAR_W; u32 py = s_origin_y + s_row * CHAR_H + CHAR_H - 2; u32 color = ToPixel(s_palette[7]); // light gray for (u32 r = 0; r < 2 && (py + r) < s_fb_h; ++r) { u32* line = s_fb + (py + r) * s_fb_stride + px; for (u32 c = 0; c < CHAR_W; ++c) line[c] = color; } s_cursor_visible = true; } // --------------------------------------------------------------------------- // Public API // --------------------------------------------------------------------------- // Show cursor at current position (call after any operation that moves the cursor) void UpdateCursor() { EraseCursor(); DrawCursorShape(); } // Toggle cursor blink -- call from PIT handler every ~50 ticks (500 ms) void BlinkCursor() { if (s_cursor_visible) EraseCursor(); else DrawCursorShape(); } // Called once from kernel_main with framebuffer from BootInfo void SetFramebuffer(u64 base, u32 w, u32 h, u32 stride, u32 fmt) { s_fb = reinterpret_cast<u32*>(base); s_fb_w = w; s_fb_h = h; s_fb_stride = stride; s_fb_bgr = (fmt == 1); // 1 = PixelBlueGreenRedReserved8BitPerColor s_origin_x = 0; s_origin_y = 0; s_cols = w / CHAR_W; if (s_cols > 256) s_cols = 256; s_rows = h / CHAR_H; if (s_rows > 64) s_rows = 64; } bool GetFramebufferInfo(FramebufferInfo& info) { if (!s_fb || s_fb_w == 0 || s_fb_h == 0) return false; info.Width = s_fb_w; info.Height = s_fb_h; info.Stride = s_fb_stride; info.Format = s_fb_bgr ? 1u : 0u; return true; } static void ResetTextSurface(u32 x, u32 y, u32 w, u32 h) { s_origin_x = x; s_origin_y = y; s_cols = w / CHAR_W; if (s_cols > 256) s_cols = 256; s_rows = h / CHAR_H; if (s_rows > 64) s_rows = 64; if (s_cols < 20) s_cols = 20; if (s_rows < 8) s_rows = 8; for (u32 r = 0; r < s_rows; ++r) for (u32 c = 0; c < s_cols; ++c) s_cells[r][c] = { ' ', 0x07 }; s_row = 1; s_col = 0; s_cursor_visible = false; } void StartDesktop(const UXTHEME::Theme& theme, const DESKTOPMODEL::DesktopLayout& layout) { if (!s_fb) return; s_mouse_visible = false; // Desktop shell mockup: XP-redesign wallpaper, icon rail, open Start menu, // taskbar, and several static shell windows around the live command window. FillVerticalGradient(0, 0, s_fb_w, s_fb_h, 0x0771D9, 0x88DFFF); FillEllipse(s_fb_w / 6, s_fb_h / 5, s_fb_w / 11, s_fb_h / 34, 0xFFFFFF); FillEllipse(s_fb_w / 4, s_fb_h / 5 - 16, s_fb_w / 13, s_fb_h / 30, 0xF4FCFF); FillEllipse((s_fb_w * 62) / 100, s_fb_h / 4, s_fb_w / 10, s_fb_h / 28, 0xF6FCFF); FillEllipse((s_fb_w * 83) / 100, s_fb_h / 5, s_fb_w / 10, s_fb_h / 34, 0xFFFFFF); u32 h1 = (s_fb_h * 63) / 100; u32 h2 = (s_fb_h * 71) / 100; u32 h3 = (s_fb_h * 79) / 100; FillVerticalGradient(0, h1, s_fb_w, s_fb_h - h1, 0x9CF264, 0x299A3C); FillVerticalGradient(0, h2, s_fb_w, s_fb_h - h2, 0x7BE754, 0x1C7F35); FillVerticalGradient(0, h3, s_fb_w, s_fb_h - h3, 0x35B944, 0x1C8A35); for (u32 x = 0; x < s_fb_w; x += 3) { u32 y = h1 + ((x * 37) % 90); if (y < s_fb_h) FillRect(x, y, 2, 3, 0xC8F7A6); } u32 task_h = s_fb_h >= 720 ? 44 : (s_fb_h >= 480 ? 38 : 30); u32 task_y = s_fb_h > task_h ? s_fb_h - task_h : 0; FillVerticalGradient(0, task_y, s_fb_w, task_h, theme.TaskbarTop, theme.TaskbarBottom); FillRect(0, task_y, s_fb_w, 1, 0x7DB7FF); DrawTextAbs(s_fb_w > 360 ? s_fb_w - 352 : 16, 28, layout.BrandName ? layout.BrandName : "MicroNT", 0xFFFFFF, 0x159DFF); DrawTextAbs(s_fb_w > 360 ? s_fb_w - 352 : 16, 48, layout.BrandTag ? layout.BrandTag : "Simply Fast. Reliably Yours.", 0xFFFFFF, 0x159DFF); u32 icon_x = 18, icon_y = 14; for (u32 i = 0; i < layout.IconCount; ++i) { u32 y = icon_y + i * 82; const DESKTOPMODEL::DesktopIcon& icon = layout.Icons[i]; switch (icon.Kind) { case DESKTOPMODEL::IconKind::Folder: DrawFolderIcon(icon_x, y, icon.Label); break; case DESKTOPMODEL::IconKind::Network: DrawDesktopIcon(icon_x, y, icon.Label, 0x0C8BE8, 0x07418D); break; case DESKTOPMODEL::IconKind::Media: DrawDesktopIcon(icon_x, y, icon.Label, 0xFF6D14, 0xFFBD4A); break; case DESKTOPMODEL::IconKind::Control: DrawDesktopIcon(icon_x, y, icon.Label, 0x46A8FF, 0x1A55B7); break; case DESKTOPMODEL::IconKind::Recycle: DrawDesktopIcon(icon_x, y, icon.Label, 0xADC4D7, 0x6E8297); break; case DESKTOPMODEL::IconKind::Computer: default: DrawDesktopIcon(icon_x, y, icon.Label, 0x439AFF, 0x12356B); break; } } for (u32 i = 0; i < layout.WindowCount; ++i) { const DESKTOPMODEL::ShellWindow& win = layout.Windows[i]; u32 x = win.X; u32 y = win.Y; u32 w = win.Width; u32 h = win.Height; if (x + w >= s_fb_w) x = s_fb_w > w + 18 ? s_fb_w - w - 18 : 12; if (y + h >= task_y) y = task_y > h + 18 ? task_y - h - 18 : 12; DrawPanelWindow(x, y, w, h, win.Title, win.Toolbar, win.Status); } u32 menu_w = s_fb_w >= 900 ? 345 : 300; u32 menu_h = s_fb_h >= 700 ? 420 : 330; u32 menu_y = task_y > menu_h ? task_y - menu_h : 0; FillRect(8 + 8, menu_y + 12, menu_w, menu_h, 0x1C3765); FillRect(8, menu_y, menu_w, menu_h, 0xFFFFFF); RectOutline(8, menu_y, menu_w, menu_h, 0x7DB7FF, 0x0C5BB9); FillVerticalGradient(9, menu_y + 1, menu_w - 2, 64, 0x1679D8, 0x0056BA); DrawFlag(24, menu_y + 18, 1); DrawTextAbs(58, menu_y + 24, "MicroNT", 0xFFFFFF, 0x0A62C0); FillRect(9, menu_y + 65, (menu_w * 53) / 100, menu_h - 103, 0xFFFFFF); FillVerticalGradient(9 + (menu_w * 53) / 100, menu_y + 65, menu_w - (menu_w * 53) / 100 - 2, menu_h - 103, 0xD9EDFF, 0x79B6ED); const char* left[] = { "Internet", "E-mail", "Media Player", "Documents", "Control Panel", "Help and Support", "Search", "Run..." }; for (u32 i = 0; i < 8; ++i) { u32 yy = menu_y + 78 + i * 34; if (i == 3) FillRect(16, yy - 5, (menu_w * 53) / 100 - 20, 28, 0xE5F2FF); DrawTextAbs(28, yy, left[i], 0x12395E, i == 3 ? 0xE5F2FF : 0xFFFFFF); } const char* right[] = { "Admin", "My Documents", "My Pictures", "My Music", "My Computer", "Control Panel", "Devices", "Defaults" }; for (u32 i = 0; i < 8; ++i) { u32 rx = 24 + (menu_w * 53) / 100; DrawTextAbs(rx, menu_y + 80 + i * 32, right[i], 0x12395E, 0xB8D9F6); } FillVerticalGradient(9, menu_y + menu_h - 38, menu_w - 2, 37, 0x1D76D2, 0x064FA8); DrawTextAbs(190, menu_y + menu_h - 25, "Log Off", 0xFFFFFF, 0x0F61B8); DrawTextAbs(254, menu_y + menu_h - 25, "Turn Off", 0xFFFFFF, 0x0F61B8); u32 start_w = s_fb_w >= 1280 ? 116 : (s_fb_w >= 640 ? 104 : 80); FillVerticalGradient(8, task_y + 5, start_w, task_h - 10, theme.StartTop, theme.StartBottom); RectOutline(8, task_y + 5, start_w, task_h - 10, 0xC6F4A5, 0x0A5A0A); DrawFlag(20, task_y + 10, 1); DrawTextAbs(56, task_y + 14, "Start", 0xFFFFFF, 0x2BA536); u32 tbx = 136; for (u32 i = 0; i < layout.WindowCount && tbx + 126 < s_fb_w; ++i) { FillVerticalGradient(tbx, task_y + 6, 125, task_h - 12, 0x4EB2F7, 0x0D53AD); RectOutline(tbx, task_y + 6, 125, task_h - 12, 0x9BC3FF, 0x0B2D8F); DrawTextAbs(tbx + 10, task_y + 15, layout.Windows[i].Title, 0xFFFFFF, 0x2A79D0); tbx += 132; } if (tbx + 126 < s_fb_w) { FillVerticalGradient(tbx, task_y + 6, 125, task_h - 12, 0x8BD1FF, 0x2475D6); RectOutline(tbx, task_y + 6, 125, task_h - 12, 0x9BC3FF, 0x0B2D8F); DrawTextAbs(tbx + 10, task_y + 15, "MicroNT Shell", 0xFFFFFF, 0x5FA2EA); } u32 tray_w = s_fb_w >= 640 ? 154 : 96; u32 tray_x = s_fb_w > tray_w ? s_fb_w - tray_w : 0; FillRect(tray_x + 4, task_y + 5, tray_w - 8, task_h - 10, 0x0A65B5); FillEllipse(tray_x + 18, task_y + task_h / 2, 6, 6, 0xA9F75B); DrawTextAbs(tray_x + 34, task_y + 14, "NET VOL 00:00", 0xFFFFFF, 0x0A65B5); u32 win_x = s_fb_w >= 1280 ? 210 : 96; u32 win_y = s_fb_h >= 900 ? 540 : 360; u32 win_w = s_fb_w >= 1280 ? 760 : s_fb_w - win_x - 24; u32 win_h = s_fb_h >= 900 ? 360 : 290; FillRect(win_x + 5, win_y + 6, win_w, win_h, 0x24508A); FillRect(win_x, win_y, win_w, win_h, theme.WindowFrame); RectOutline(win_x, win_y, win_w, win_h, 0xFFFFFF, 0x315BA3); FillVerticalGradient(win_x + 3, win_y + 3, win_w - 6, 28, theme.WindowTitleTop, theme.WindowTitleBottom); DrawTextAbs(win_x + 12, win_y + 9, "MicroNT Command Prompt", 0xFFFFFF, 0x1C5DE4); u32 bx = win_x + win_w - 76; for (u32 i = 0; i < 3; ++i) { FillVerticalGradient(bx + i * 23, win_y + 7, 19, 18, 0x75A7FF, 0x1E55CF); RectOutline(bx + i * 23, win_y + 7, 19, 18, 0xC7DEFF, 0x0D2D89); } DrawTextAbs(bx + 6, win_y + 8, "_", 0xFFFFFF, 0x4D83EF); DrawTextAbs(bx + 29, win_y + 8, "o", 0xFFFFFF, 0x4D83EF); DrawTextAbs(bx + 52, win_y + 8, "x", 0xFFFFFF, 0x4D83EF); u32 client_x = win_x + 8; u32 client_y = win_y + 36; u32 client_w = win_w > 16 ? win_w - 16 : win_w; u32 client_h = win_h > 72 ? win_h - 72 : win_h; FillRect(client_x, client_y, client_w, client_h, 0x000000); RectOutline(client_x - 1, client_y - 1, client_w + 2, client_h + 2, 0x7F9DB9, 0xFFFFFF); FillRect(win_x + 8, win_y + win_h - 28, win_w - 16, 20, theme.WindowFrame); RectOutline(win_x + 8, win_y + win_h - 28, win_w - 16, 20, 0xFFFFFF, 0xACA899); ResetTextSurface(client_x, client_y, client_w, client_h); const char hdr[] = "*** MicroNT Shell - Windows XP style ***"; u32 hlen = sizeof(hdr) - 1; u32 hstart = (s_cols > hlen) ? (s_cols - hlen) / 2 : 0; for (u32 c = 0; c < s_cols; ++c) s_cells[0][c] = { ' ', 0x1F }; for (u32 i = 0; i < hlen && hstart + i < s_cols; ++i) s_cells[0][hstart + i] = { (u8)hdr[i], 0x1F }; RedrawAll(); DrawTextAbs(win_x + 12, win_y + win_h - 23, "Ready 1920 x 1080 desktop target", 0x000000, theme.WindowFrame); MoveMouseCursor(s_fb_w > 240 ? s_fb_w - 220 : win_x + win_w - 82, h1 > 140 ? h1 - 120 : win_y + 74); } void MoveMouseCursor(u32 x, u32 y) { if (!s_fb) return; RestoreMouseCursor(); u32 max_x = s_fb_w > 24 ? s_fb_w - 24 : 0; u32 max_y = s_fb_h > 32 ? s_fb_h - 32 : 0; if (x > max_x) x = max_x; if (y > max_y) y = max_y; s_mouse_x = x; s_mouse_y = y; SaveMouseCursor(s_mouse_x, s_mouse_y); DrawMouseCursor(s_mouse_x, s_mouse_y); s_mouse_visible = true; } void Init() { if (!s_fb) return; s_origin_x = 0; s_origin_y = 0; s_cols = s_fb_w / CHAR_W; if (s_cols > 256) s_cols = 256; s_rows = s_fb_h / CHAR_H; if (s_rows > 64) s_rows = 64; s_cursor_visible = false; s_mouse_visible = false; // Erase the entire GPU framebuffer to solid black first, // so no OVMF splash/watermark bleeds through below the text area. u32 black = ToPixel(0x000000); for (u32 y = 0; y < s_fb_h; ++y) { u32* row = s_fb + y * s_fb_stride; for (u32 x = 0; x < s_fb_w; ++x) row[x] = black; } // Clear text cell buffer for (u32 r = 0; r < s_rows; ++r) for (u32 c = 0; c < s_cols; ++c) s_cells[r][c] = { ' ', 0x07 }; // Header bar (row 0): blue bg, bright white fg -- centered over actual width const char hdr[] = "*** MicroNT Kernel M28 ***"; constexpr u32 hlen = sizeof(hdr) - 1; u32 hstart = (s_cols > hlen) ? (s_cols - hlen) / 2 : 0; for (u32 c = 0; c < s_cols; ++c) s_cells[0][c] = { ' ', 0x1F }; for (u32 i = 0; i < hlen; ++i) s_cells[0][hstart + i] = { (u8)hdr[i], 0x1F }; // Render everything RedrawAll(); s_row = 1; s_col = 0; } // ClearScreen: fast clear for the 'clear' shell command. // Keeps the header bar (row 0), blanks rows 1+ and resets cursor. void ClearScreen() { if (!s_fb) return; EraseCursor(); for (u32 r = 1; r < s_rows; ++r) for (u32 c = 0; c < s_cols; ++c) s_cells[r][c] = { ' ', 0x07 }; // Repaint rows 1+ to the framebuffer for (u32 r = 1; r < s_rows; ++r) for (u32 c = 0; c < s_cols; ++c) DrawChar(c, r, ' ', 7, 0); s_row = 1; s_col = 0; DrawCursorShape(); } void WriteWelcome() { if (!s_fb) return; const char l1[] = " MicroNT Microkernel - Build M28"; const char l2[] = " ==================================="; const char l3[] = " All systems online. Ready for input."; const char l4[] = " Commands: ver dir mem ps exec cat echo write clear pipe help exit"; auto writeln = [&](u32 row, const char* s, u8 attr) { for (u32 c = 0; c < s_cols && s[c]; ++c) SetCell(row, c, (u8)s[c], attr); }; writeln(2, l1, 0x0E); // yellow writeln(3, l2, 0x0A); // green writeln(4, l3, 0x0F); // bright white writeln(5, l4, 0x0B); // cyan s_row = 7; s_col = 0; UpdateCursor(); } void Print(const char* s, u8 attr) { for (; *s; ++s) PutChar(*s, attr); } // Print a [USER] line: always at column 0 of s_row // ---- M31: visual memory bar ----------------------------------------- // Parse an unsigned decimal from buf[i..], advance i, return value. static u64 ParseU64(const char* buf, u32 len, u32& i) { u64 v = 0; while (i < len && buf[i] >= '0' && buf[i] <= '9') v = v*10 + (buf[i++]-'0'); return v; } // Draw a number right-aligned into cells at (row, col), returns end col. static u32 CellNum(u32 row, u32 col, u64 v, u8 attr) { char tmp[20]; u32 n = 0; if (v == 0) { tmp[n++] = '0'; } else { u64 x = v; while(x){ tmp[n++]='0'+(u8)(x%10); x/=10; } } // reverse for (u32 a=0,b=n-1; a<b; ++a,--b) { char t=tmp[a]; tmp[a]=tmp[b]; tmp[b]=t; } for (u32 j = 0; j < n && col < s_cols; ++j, ++col) SetCell(row, col, (u8)tmp[j], attr); return col; } // Render multi-row visual memory panel. Returns true if it consumed the line. static bool TryDrawMemBar(const char* buf, u32 len) { // Expects: "Memory: Free=F KB Used=U KB Total=T KB Pages=P/Q" if (len < 7 || buf[0]!='M'||buf[1]!='e'||buf[2]!='m'|| buf[3]!='o'||buf[4]!='r'||buf[5]!='y'||buf[6]!=':') return false; u64 free_kb=0, used_kb=0, total_kb=0, used_pages=0, total_pages=0; for (u32 i = 7; i < len; ) { // Skip to next letter while (i < len && (buf[i]==' '||buf[i]=='\t')) ++i; if (i >= len) break; // Match keyword=value auto match = [&](const char* kw) { u32 k=0; u32 j=i; while (kw[k] && j<len && buf[j]==kw[k]) { ++k; ++j; } if (!kw[k]) { i=j; return true; } return false; }; if (match("Free=")) { free_kb = ParseU64(buf,len,i); } else if (match("Used=")) { used_kb = ParseU64(buf,len,i); } else if (match("Total=")) { total_kb = ParseU64(buf,len,i); } else if (match("Pages=")) { used_pages = ParseU64(buf,len,i); if (i < len && buf[i]=='/') { ++i; total_pages = ParseU64(buf,len,i); } } else ++i; // skip one char } if (total_kb == 0) return false; u32 max_row = s_rows > 1 ? s_rows - 2 : 1; EraseCursor(); // Helper: fill a row from col c with string s in attr, blank the rest auto rowstr = [&](u32 r, u32 c, const char* s, u8 attr) { for (; *s && c < s_cols; ++s, ++c) SetCell(r, c, (u8)*s, attr); for (; c < s_cols; ++c) SetCell(r, c, ' ', 0x07); }; auto advance = [&]() { if (s_row > max_row) Scroll(); }; // ---- Row 1: title ---- advance(); rowstr(s_row, 0, " Memory Map", 0x0B); // cyan ++s_row; // ---- Row 2: bar ---- advance(); u32 bar_w = s_cols > 24 ? s_cols - 22 : 10; u64 pct = total_kb ? (used_kb * 100) / total_kb : 0; u32 filled = (u32)((pct * bar_w) / 100); u32 c = 0; SetCell(s_row, c++, ' ', 0x07); SetCell(s_row, c++, ' ', 0x07); SetCell(s_row, c++, '[', 0x0F); for (u32 k = 0; k < bar_w; ++k, ++c) { // 0xA0 = light-green bg / 0x80 = dark-gray bg, space char SetCell(s_row, c, ' ', k < filled ? 0xA0u : 0x80u); } SetCell(s_row, c++, ']', 0x0F); SetCell(s_row, c++, ' ', 0x07); // Percentage: "XX%" c = CellNum(s_row, c, pct, 0x0F); SetCell(s_row, c++, '%', 0x07); // Pad rest for (; c < s_cols; ++c) SetCell(s_row, c, ' ', 0x07); ++s_row; // ---- Row 3: KB detail ---- advance(); { const char* lab = " Used: "; u32 cc = 0; for (; *lab && cc < s_cols; ++lab, ++cc) SetCell(s_row, cc, (u8)*lab, 0x08); cc = CellNum(s_row, cc, used_kb, 0x0F); const char* sep1 = " KB Free: "; for (; *sep1 && cc < s_cols; ++sep1, ++cc) SetCell(s_row, cc, (u8)*sep1, 0x08); cc = CellNum(s_row, cc, free_kb, 0x0A); const char* sep2 = " KB Total: "; for (; *sep2 && cc < s_cols; ++sep2, ++cc) SetCell(s_row, cc, (u8)*sep2, 0x08); cc = CellNum(s_row, cc, total_kb, 0x0B); const char* sfx = " KB"; for (; *sfx && cc < s_cols; ++sfx, ++cc) SetCell(s_row, cc, (u8)*sfx, 0x08); for (; cc < s_cols; ++cc) SetCell(s_row, cc, ' ', 0x07); ++s_row; } // ---- Row 4: page detail (if we have page data) ---- if (total_pages > 0) { advance(); const char* lab = " Pages: Used="; u32 cc = 0; for (; *lab && cc < s_cols; ++lab, ++cc) SetCell(s_row, cc, (u8)*lab, 0x08); cc = CellNum(s_row, cc, used_pages, 0x0F); const char* sep = " Free="; for (; *sep && cc < s_cols; ++sep, ++cc) SetCell(s_row, cc, (u8)*sep, 0x08); u64 free_pages = (used_pages <= total_pages) ? (total_pages - used_pages) : 0; cc = CellNum(s_row, cc, free_pages, 0x0A); const char* sep2 = " Total="; for (; *sep2 && cc < s_cols; ++sep2, ++cc) SetCell(s_row, cc, (u8)*sep2, 0x08); cc = CellNum(s_row, cc, total_pages, 0x0B); for (; cc < s_cols; ++cc) SetCell(s_row, cc, ' ', 0x07); ++s_row; } s_col = 0; DrawCursorShape(); return true; } static u8 ContentColor(const char* buf, u32 len) { if (len == 0) return 0x0F; // Directory entries are wrapped in [brackets] by NT_QUERY_DIR if (len >= 3 && buf[0] == '[' && buf[len-1] == ']') return 0x0E; // yellow // File extensions (last 4 chars) if (len >= 4) { const char* e = buf + len - 4; if (e[0]=='.' && (e[1]|32)=='e' && (e[2]|32)=='x' && (e[3]|32)=='e') return 0x0A; // .EXE green if (e[0]=='.' && (e[1]|32)=='t' && (e[2]|32)=='x' && (e[3]|32)=='t') return 0x0E; // .txt yellow if (e[0]=='.' && ((e[1]|32)=='i' || (e[1]|32)=='c')) return 0x0B; // .ini/.cfg cyan } // Prefix detection if (len>=3 && buf[0]=='M' && buf[1]=='i' && buf[2]=='c') return 0x0D; // MicroNT -> magenta if (len>=3 && buf[0]=='M' && buf[1]=='e' && buf[2]=='m') return 0x0B; // Memory -> cyan if (len>=3 && buf[0]=='S' && buf[1]=='y' && buf[2]=='s') return 0x0B; // System -> cyan if (len>=3 && buf[0]=='T' && buf[1]=='h' && buf[2]=='r') return 0x0B; // Thread -> cyan if (len>=2 && buf[0]=='O' && buf[1]=='K') return 0x0A; // OK -> green if (len>=3 && (buf[0]|32)=='e' && (buf[1]|32)=='r' && (buf[2]|32)=='r') return 0x0C; // Err -> red return 0x0F; // default bright white } void PrintUser(const char* buf, usize len) { EraseCursor(); u32 max_row = s_rows > 1 ? s_rows - 2 : 1; if (s_row < 1) s_row = 1; if (s_row > max_row) Scroll(); // Count printable content (stop at first \n, \r, or \0) u32 content_len = 0; for (u32 i = 0; i < len && buf[i] && buf[i] != '\n' && buf[i] != '\r'; ++i) ++content_len; // Empty / pure-newline write: skip silently (suppresses blank rows between // dir entries that the shell emits as separate '\n' writes). if (content_len == 0) { DrawCursorShape(); return; } // M31 fix: detect the shell's "> " prompt specifically. // Show it as "[USER] > " with cursor held on the same row so typed // characters follow on that line. Every other write is plain output. if (content_len == 2 && buf[0] == '>' && buf[1] == ' ') { u32 col = 0; const char* pre = "[USER] "; for (; *pre && col < s_cols; ++pre, ++col) SetCell(s_row, col, (u8)*pre, 0x0B); SetCell(s_row, col++, '>', 0x0F); SetCell(s_row, col++, ' ', 0x07); for (u32 c = col; c < s_cols; ++c) SetCell(s_row, c, ' ', 0x07); s_col = col; // cursor right after "> " DrawCursorShape(); return; } // M31: intercept "Memory: ..." and render visual bar panel if (TryDrawMemBar(buf, content_len)) return; u8 color = ContentColor(buf, content_len); u32 col = 0; for (u32 i = 0; i < content_len && col < s_cols; ++i, ++col) SetCell(s_row, col, (u8)buf[i], color); for (; col < s_cols; ++col) SetCell(s_row, col, ' ', 0x07); if (++s_row > max_row) Scroll(); s_col = 0; DrawCursorShape(); } // --------------------------------------------------------------------------- // M29: Live status bar // --------------------------------------------------------------------------- // Render one row of cells to the framebuffer (used for targeted redraws). static void RedrawRow(u32 r) { for (u32 c = 0; c < s_cols; ++c) { Cell& cell = s_cells[r][c]; DrawChar(c, r, cell.ch, AttrFg(cell.attr), AttrBg(cell.attr)); } } // Decimal format helpers (no libc). static void FmtU64(char* buf, u64 v, u32 width, char pad) { char tmp[20]; u32 n = 0; do { tmp[n++] = '0' + (v % 10); v /= 10; } while (v); u32 total = n > width ? n : width; for (u32 i = 0; i < total - n; ++i) *buf++ = pad; for (u32 i = n; i > 0; --i) *buf++ = tmp[i-1]; *buf = 0; } // Called from PIT every 100 ticks (~1 s). Updates: // Row 0 right side: "Up: HH:MM:SS" // Row s_rows-1 : status bar with keyboard hints void UpdateStatusBar(u64 ticks) { if (!s_fb || s_cols < 20) return; // ---- uptime in header (row 0, right-aligned) ---- u64 secs = ticks / 100; u64 mins = secs / 60; secs %= 60; u64 hrs = mins / 60; mins %= 60; char up[20] = "Up: "; char tmp[8]; FmtU64(tmp, hrs, 2, '0'); for (u32 i=0;tmp[i];++i) up[4+i]=tmp[i]; up[6]=':'; FmtU64(tmp, mins, 2, '0'); up[7]=tmp[0]; up[8]=tmp[1]; up[9]=':'; FmtU64(tmp, secs, 2, '0'); up[10]=tmp[0]; up[11]=tmp[1]; up[12]=0; u32 uplen = 12; // "Up: HH:MM:SS" u32 upcol = s_cols > uplen + 1 ? s_cols - uplen - 1 : 0; for (u32 i = 0; i < uplen && upcol + i < s_cols; ++i) s_cells[0][upcol + i] = { (u8)up[i], 0x1F }; RedrawRow(0); // ---- bottom status bar (last row) ---- u32 bot = s_rows - 1; // Fill with dark background (black bg, dark gray fg = 0x08) for (u32 c = 0; c < s_cols; ++c) s_cells[bot][c] = { ' ', 0x78 }; // white on gray const char* hints = " Tab: complete Up/Down: history clear: reset screen help: commands "; u32 col = 0; for (const char* p = hints; *p && col < s_cols; ++p, ++col) s_cells[bot][col] = { (u8)*p, 0x78 }; RedrawRow(bot); } } // namespace VGA