diff --git a/Makefile b/Makefile index b3e2ce2..f74351a 100644 --- a/Makefile +++ b/Makefile @@ -12,18 +12,23 @@ CFLAGS = -m32 -ffreestanding -O2 -Wall -Wextra \ -I./src ASFLAGS = -f elf32 LDFLAGS = -m elf_i386 -T linker.ld -nostdlib - +BMP_FILES := $(wildcard assets/*.bmp) +BMP_OBJS := $(patsubst assets/%.bmp, assets/%.o, $(BMP_FILES)) # Файлы SOURCES = $(wildcard src/*.c) ASM_SOURCES = $(wildcard src/*.asm) -OBJECTS = src/boot.o $(SOURCES:.c=.o) $(ASM_SOURCES:.asm=.o) +OBJECTS = $(patsubst %.c,%.o,$(wildcard src/*.c)) $(patsubst %.asm,%.o,$(wildcard src/*.asm)) TARGET = kernel.bin all: $(TARGET) iso +assets/%.o: assets/%.bmp + @mkdir -p assets + objcopy -I binary -O elf32-i386 -B i386 $< $@ + # Сборка ядра -$(TARGET): $(OBJECTS) - $(LD) $(LDFLAGS) -o $@ $^ +$(TARGET): $(OBJECTS) $(BMP_OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJECTS) $(BMP_OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ @@ -41,5 +46,5 @@ run: iso qemu-system-i386 -vga std -cdrom zalupa.iso -serial stdio -monitor none #-d int,cpu_reset -no-reboot -no-shutdown clean: - rm -f src/*.o $(TARGET) zalupa.iso + rm -f src/*.o assets/*.o $(TARGET) zalupa.iso rm -rf iso/boot/$(TARGET) diff --git a/README.md b/README.md index dd07dd7..f502376 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ ZalupaCalc 2 - это инновационная операционная сис - [x] Вывод на экран попиксельно - [x] Вывод на экран прямоугольников и прочих фигур -- [ ] Вывод на экран BMP +- [x] Вывод на экран BMP - [ ] Вывод на экран текста - [ ] Двойная буферизация - [ ] Вывод курсора мыши на экран, движение diff --git a/assets/bg.bmp b/assets/bg.bmp new file mode 100644 index 0000000..418b0a8 Binary files /dev/null and b/assets/bg.bmp differ diff --git a/assets/cursor.bmp b/assets/cursor.bmp new file mode 100644 index 0000000..e3fdacc Binary files /dev/null and b/assets/cursor.bmp differ diff --git a/src/drawing.c b/src/drawing.c index b108790..c09c4f2 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -2,6 +2,7 @@ #include "multiboot.h" #include "serial.h" #include "vmm.h" // Для маппинга +#define TRANSPARENT_COLOR 0xFF00FF uint32_t* fb_ptr = 0; uint32_t screen_width = 0; @@ -52,3 +53,82 @@ void clear_screen(uint32_t color) { fb_ptr[i] = color; } } + +#pragma pack(push, 1) +struct bmp_header { + uint16_t type; + uint32_t size; + uint16_t reserved1; + uint16_t reserved2; + uint32_t offset; +}; + +struct dib_header { + uint32_t size; + int32_t width; + int32_t height; + uint16_t planes; + uint16_t bpp; + uint32_t compression; + uint32_t image_size; + int32_t x_ppm; + int32_t y_ppm; + uint32_t colors_used; + uint32_t colors_important; +}; +#pragma pack(pop) + +void draw_bmp(uint8_t* data, int x, int y) { + struct bmp_header* bh = (struct bmp_header*)data; + struct dib_header* dh = (struct dib_header*)(data + sizeof(struct bmp_header)); + + int w = dh->width; + int h = dh->height; + + // 24-битный BMP: каждый ряд выровнен по 4 байтам + // Считаем размер ряда в байтах + int row_size = (w * 3 + 3) & ~3; + uint8_t* pixels = data + bh->offset; + + for (int i = 0; i < h; i++) { + // BMP хранятся снизу вверх, поэтому i идет от 0 до h, + // а рисуем мы начиная с y + h - 1 + int draw_y = y + (h - 1 - i); + + for (int j = 0; j < w; j++) { + // Берем 3 байта BGR + uint8_t* pixel_ptr = pixels + (i * row_size) + (j * 3); + uint8_t b = pixel_ptr[0]; + uint8_t g = pixel_ptr[1]; + uint8_t r = pixel_ptr[2]; + + // Собираем в 0x00RRGGBB + uint32_t color = (r << 16) | (g << 8) | b; + + put_pixel(x + j, draw_y, color); + } + } +} + +void draw_cursor_sprite(uint8_t* bmp_data, int x, int y) { + struct bmp_header* bh = (struct bmp_header*)bmp_data; + struct dib_header* dh = (struct dib_header*)(bmp_data + sizeof(struct bmp_header)); + + uint8_t* pixels = bmp_data + bh->offset; + int w = dh->width; + int h = dh->height; + int row_size = (w * 3 + 3) & ~3; + + for (int i = 0; i < h; i++) { + int draw_y = y + (h - 1 - i); + for (int j = 0; j < w; j++) { + uint8_t* p = pixels + (i * row_size) + (j * 3); + uint32_t color = (p[2] << 16) | (p[1] << 8) | p[0]; + + // Если цвет не прозрачный — рисуем + if (color != TRANSPARENT_COLOR) { + put_pixel(x + j, draw_y, color); + } + } + } +} diff --git a/src/drawing.h b/src/drawing.h index c39bb3d..466068b 100644 --- a/src/drawing.h +++ b/src/drawing.h @@ -13,5 +13,7 @@ void draw_init(struct multiboot_info* mbi); void put_pixel(int x, int y, uint32_t color); 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); #endif diff --git a/src/kmain.c b/src/kmain.c index 4240ee8..e298431 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -18,6 +18,9 @@ uint32_t color_sky_blue = 0x0087CEEB; uint32_t color_orange = 0x00FFA500; uint32_t color_white = 0x00FFFFFF; uint32_t color_black = 0x00000000; +extern uint8_t _binary_assets_logo_bmp_start[]; +extern uint8_t _binary_assets_bg_bmp_start[]; +extern uint8_t _binary_assets_cursor_bmp_start[]; extern uint32_t _kernel_end; // Символ 'end' прописан в конце любого стандартного linker.ld uint32_t kernel_end = (uint32_t)&_kernel_end; @@ -194,17 +197,15 @@ void kernel_main(uint32_t mboot_addr, uint32_t magic) { speaker_beep(325, 10); speaker_beep(350, 400); log_info(LOG_NORMAL, "OK!"); - clear_screen(bg_color); int old_mouse_x = 0; int old_mouse_y = 0; while (1) { if (mouse_x != old_mouse_x || mouse_y != old_mouse_y) { // Стираем старый - draw_rect(old_mouse_x - 5, old_mouse_y - 5, 10, 10, bg_color); + draw_bmp(_binary_assets_bg_bmp_start, 0, 0); // Рисуем новый - int color = left_click ? color_orange : (right_click ? color_sky_blue : color_white); - draw_rect(mouse_x - 5, mouse_y - 5, 10, 10, color); + draw_cursor_sprite(_binary_assets_cursor_bmp_start, mouse_x, mouse_y); old_mouse_x = mouse_x; old_mouse_y = mouse_y;