diff --git a/README.md b/README.md index f502376..366c291 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ ZalupaCalc 2 - это инновационная операционная сис - [x] Вывод на экран попиксельно - [x] Вывод на экран прямоугольников и прочих фигур - [x] Вывод на экран BMP -- [ ] Вывод на экран текста +- [x] Вывод на экран текста - [ ] Двойная буферизация - [ ] Вывод курсора мыши на экран, движение - [ ] Кнопки (touch zones, массив в памяти где будут координаты областей и действия при нажатии) diff --git a/src/drawing.c b/src/drawing.c index c09c4f2..1d5d215 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -2,6 +2,7 @@ #include "multiboot.h" #include "serial.h" #include "vmm.h" // Для маппинга +#include "font.h" #define TRANSPARENT_COLOR 0xFF00FF uint32_t* fb_ptr = 0; @@ -132,3 +133,35 @@ void draw_cursor_sprite(uint8_t* bmp_data, int x, int y) { } } } + +void put_char(char c, int x, int y, uint32_t color) { + if (c < 32 || c > 126) c = 32; // Если символ вне диапазона — рисуем пробел + + const uint8_t* glyph = font8x8[c - 32]; + + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + // Если бит в строке установлен — рисуем пиксель + if (glyph[i] & (1 << (7 - j))) { + put_pixel(x + j, y + i, color); + } + } + } +} + +void draw_string(const char* str, int x, int y, uint32_t color) { + int cursor_x = x; + int cursor_y = y; + + while (*str != '\0') { + // Если встретили символ переноса строки + if (*str == '\n') { + cursor_x = x; + cursor_y += 10; // 8 пикселей высота буквы + 2 пикселя отступ + } else { + put_char(*str, cursor_x, cursor_y, color); + cursor_x += 9; // 8 пикселей ширина буквы + 1 пиксель пробел между ними + } + str++; + } +} diff --git a/src/drawing.h b/src/drawing.h index 466068b..b0249fd 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -15,5 +15,7 @@ void draw_rect(int x, int y, int w, int h, uint32_t color); void clear_screen(uint32_t color); void draw_bmp(uint8_t* data, int x, int y); void draw_cursor_sprite(uint8_t* bmp_data, int x, int y); +void put_char(char c, int x, int y, uint32_t color); +void draw_string(const char* str, int x, int y, uint32_t color); #endif diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..be4cdf7 --- /dev/null +++ b/src/font.c @@ -0,0 +1,99 @@ +#include + +const uint8_t font8x8[95][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 32 + {0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x00}, // 33 ! + {0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00}, // 34 " + {0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, 0x00}, // 35 # + {0x18, 0x7E, 0xFF, 0x1B, 0x1B, 0x1B, 0x1B, 0x00}, // 36 $ + {0x63, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x63, 0x00}, // 37 % + {0x3C, 0x66, 0x3C, 0x6B, 0x33, 0x66, 0x3C, 0x00}, // 38 & + {0x06, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00}, // 39 ' + {0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00}, // 40 ( + {0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00}, // 41 ) + {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // 42 * + {0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00}, // 43 + + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30}, // 44 , + {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}, // 45 - + {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}, // 46 . + {0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00}, // 47 / + {0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // 48 0 + {0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00}, // 49 1 + {0x3C, 0x66, 0x06, 0x1C, 0x30, 0x66, 0x7E, 0x00}, // 50 2 + {0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00}, // 51 3 + {0x0C, 0x1C, 0x3C, 0x6C, 0x7E, 0x0C, 0x0C, 0x00}, // 52 4 + {0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00}, // 53 5 + {0x3C, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x3C, 0x00}, // 54 6 + {0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00}, // 55 7 + {0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00}, // 56 8 + {0x3C, 0x66, 0x66, 0x7C, 0x06, 0x66, 0x3C, 0x00}, // 57 9 + {0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00}, // 58 : + {0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30}, // 59 ; + {0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00}, // 60 < + {0x00, 0x00, 0x7E, 0x00, 0x7E, 0x00, 0x00, 0x00}, // 61 = + {0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00}, // 62 > + {0x3C, 0x66, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00}, // 63 ? + {0x3C, 0x66, 0x76, 0x76, 0x76, 0x60, 0x3C, 0x00}, // 64 @ + {0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00}, // 65 A + {0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00}, // 66 B + {0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00}, // 67 C + {0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00}, // 68 D + {0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x7E, 0x00}, // 69 E + {0x7E, 0x60, 0x60, 0x78, 0x60, 0x60, 0x60, 0x00}, // 70 F + {0x3C, 0x66, 0x60, 0x6E, 0x66, 0x66, 0x3C, 0x00}, // 71 G + {0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00}, // 72 H + {0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, // 73 I + {0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38, 0x00}, // 74 J + {0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00}, // 75 K + {0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00}, // 76 L + {0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00}, // 77 M + {0x63, 0x73, 0x7B, 0x6F, 0x67, 0x63, 0x63, 0x00}, // 78 N + {0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // 79 O + {0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x00}, // 80 P + {0x3C, 0x66, 0x66, 0x66, 0x76, 0x3C, 0x0E, 0x00}, // 81 Q + {0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00}, // 82 R + {0x3C, 0x66, 0x60, 0x3C, 0x06, 0x66, 0x3C, 0x00}, // 83 S + {0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, // 84 T + {0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00}, // 85 U + {0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, // 86 V + {0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // 87 W + {0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00}, // 88 X + {0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00}, // 89 Y + {0x7E, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x7E, 0x00}, // 90 Z + {0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00}, // 91 [ + {0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // 92 \ + {0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00}, // 93 ] + {0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00}, // 94 ^ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // 95 _ + {0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00}, // 96 ` + {0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3B, 0x00}, // 97 a + {0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00}, // 98 b + {0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00}, // 99 c + {0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3B, 0x00}, // 100 d + {0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00}, // 101 e + {0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x30, 0x00}, // 102 f + {0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x3C}, // 103 g + {0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00}, // 104 h + {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00}, // 105 i + {0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x6C, 0x38}, // 106 j + {0x60, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00}, // 107 k + {0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00}, // 108 l + {0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xD6, 0xC6, 0x00}, // 109 m + {0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00}, // 110 n + {0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00}, // 111 o + {0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60}, // 112 p + {0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x06}, // 113 q + {0x00, 0x00, 0x6E, 0x76, 0x60, 0x60, 0x60, 0x00}, // 114 r + {0x00, 0x00, 0x3C, 0x60, 0x3C, 0x06, 0x3C, 0x00}, // 115 s + {0x30, 0x30, 0x7C, 0x30, 0x30, 0x36, 0x1C, 0x00}, // 116 t + {0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00}, // 117 u + {0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00}, // 118 v + {0x00, 0x00, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // 119 w + {0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00}, // 120 x + {0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x06, 0x3C}, // 121 y + {0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00}, // 122 z + {0x0E, 0x18, 0x18, 0x18, 0x3C, 0x18, 0x18, 0x0E}, // 123 { + {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, // 124 | + {0x70, 0x18, 0x18, 0x18, 0x3C, 0x18, 0x18, 0x70}, // 125 } + {0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // 126 ~ +}; diff --git a/src/font.h b/src/font.h new file mode 100644 index 0000000..72bf09b --- /dev/null +++ b/src/font.h @@ -0,0 +1,10 @@ +// font.h +#ifndef FONT_H +#define FONT_H + +#include + +// Массив содержит 95 символов (от пробела до '~'), каждый по 8 байт +extern const uint8_t font8x8[95][8]; + +#endif diff --git a/src/kmain.c b/src/kmain.c index e298431..acdf467 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -22,6 +22,10 @@ extern uint8_t _binary_assets_logo_bmp_start[]; extern uint8_t _binary_assets_bg_bmp_start[]; extern uint8_t _binary_assets_cursor_bmp_start[]; +uint32_t frame_count = 0; // Сколько раз отрисовали за секунду +uint32_t last_fps_ticks = 0; // Когда последний раз обновляли FPS +uint32_t current_fps = 0; // Результат (число FPS) + extern uint32_t _kernel_end; // Символ 'end' прописан в конце любого стандартного linker.ld uint32_t kernel_end = (uint32_t)&_kernel_end; @@ -199,16 +203,25 @@ void kernel_main(uint32_t mboot_addr, uint32_t magic) { log_info(LOG_NORMAL, "OK!"); int old_mouse_x = 0; int old_mouse_y = 0; + char fpsbuf[4]; while (1) { - if (mouse_x != old_mouse_x || mouse_y != old_mouse_y) { - // Стираем старый - draw_bmp(_binary_assets_bg_bmp_start, 0, 0); - - // Рисуем новый - draw_cursor_sprite(_binary_assets_cursor_bmp_start, mouse_x, mouse_y); - - old_mouse_x = mouse_x; - old_mouse_y = mouse_y; + // 1. Всегда рисуем фон и элементы + draw_bmp(_binary_assets_bg_bmp_start, 0, 0); + draw_cursor_sprite(_binary_assets_cursor_bmp_start, mouse_x, mouse_y); + + // 2. Всегда рисуем FPS + draw_string("FPS: ", 0, 0, color_white); + itoa(current_fps, fpsbuf, 10); + draw_string(fpsbuf, 40, 0, color_white); + + // 3. Считаем кадр + frame_count++; + + // 4. Логика обновления FPS (раз в секунду) + if (system_ticks - last_fps_ticks >= 100) { + current_fps = frame_count; + frame_count = 0; + last_fps_ticks = system_ticks; } } } diff --git a/src/string.c b/src/string.c index 3233f8f..55cc742 100644 --- a/src/string.c +++ b/src/string.c @@ -116,52 +116,43 @@ int atoi(const char* str) { // Число в строку (поддерживает base = 10 и base = 2) char* itoa(int value, char* str, int base) { int i = 0; + + // Используем unsigned, чтобы безопасно обрабатывать MIN_INT + unsigned int n; int is_negative = 0; - // Защита от дурака - if (base < 2 || base > 36) { - str[0] = '\0'; - return str; + if (base < 2 || base > 36) { str[0] = '\0'; return str; } + + if (value < 0 && base == 10) { + is_negative = 1; + n = (unsigned int)(-value); // Приводим к unsigned перед инверсией + } else { + n = (unsigned int)value; } - // Обрабатываем 0 - if (value == 0) { + if (n == 0) { str[i++] = '0'; str[i] = '\0'; return str; } - // Отрицательные числа обрабатываем только для десятичной системы - if (value < 0 && base == 10) { - is_negative = 1; - value = -value; - } - - // Переводим число в строку (но она получится задом наперед) - while (value != 0) { - int rem = value % base; + while (n != 0) { + int rem = n % base; str[i++] = (rem > 9) ? (rem - 10) + 'a' : rem + '0'; - value = value / base; - } - - // Добавляем минус - if (is_negative) { - str[i++] = '-'; + n /= base; } + if (is_negative) str[i++] = '-'; str[i] = '\0'; - // Переворачиваем строку в нормальный вид - int start = 0; - int end = i - 1; + // Разворот (этот кусок у тебя верный) + int start = 0, end = i - 1; while (start < end) { char temp = str[start]; str[start] = str[end]; str[end] = temp; - start++; - end--; + start++; end--; } - return str; }