diff --git a/doc/MEMORY_MAP.md b/doc/MEMORY_MAP.md index 53d4f4c..984fdb1 100644 --- a/doc/MEMORY_MAP.md +++ b/doc/MEMORY_MAP.md @@ -10,11 +10,13 @@ The processor starts in Real Mode, addressing 1 MB of memory. | :--- | :--- | :--- | :--- | :--- | :--- | | **`0x00000`** | **`0x003FF`** | 1 KB | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` | | **`0x00400`** | **`0x004FF`** | 256 B | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` | -| **`0x00500`** | **`0x005FF`** | 256 B | **Custom BDA** (Driver Data) | `0x0050` | `memory.asm` | -| **`0x00600`** | **`0x00AFF`** | 1.25 KB | **GUI RAM** (Widget Allocation) | `0x0060` | `gui/lib.asm` | -| **`0x00B00`** | **`0x07FFF`** | 29 KB | **Free** (Low Memory) | | | +| **`0x00500`** | **`0x006FF`** | ~512 B | **Custom BDA** (Driver Data) | `0x0050` | | +| **`0x00700`** | **`0x00A6F`** | ~1792 B | **GUI RAM** (Widget Allocation) | **`0x0070`** | `gui/lib-api.asm` | +| **`0x00A70`** | **`0x07FFF`** | ~ 29 KB | **Free** (Low Memory) | | | | **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `boot.asm` | -| **`0x18000`** | **`0x9FFFF`** | 544 KB | **Free** (Conventional RAM) | | | +| **`0x18000`** | **`0x1FFFF`** | 32 KB | **Free** | | | +| **`0x20000`** | **`0x2FFFF`** | 64 KB | **Heap** (Dynamic Allocation) | `0x2000` | `memory.asm` | +| **`0x30000`** | **`0x9FFFF`** | 448 KB | **Free** (Conventional RAM) | | | | **`0xA0000`** | **`0xAFFFF`** | 64 KB | **VGA RAM** (Graphics Modes) | `0xA000` | `Hardware` | | **`0xB0000`** | **`0xB7FFF`** | 32 KB | **MDA RAM** (Monochrome Text) | `0xB000` | `Hardware` | | **`0xB8000`** | **`0xBFFFF`** | 32 KB | **VRAM** (CGA / MCGA) | `0xB800` | `generic.asm` | @@ -35,11 +37,11 @@ The processor starts in Real Mode, addressing 1 MB of memory. The project separates the standard IBM BDA from its own variables to avoid conflicts with the VGA BIOS loaded at `0xC000`. * **Standard BDA (`0040:0000`)**: Used mainly by the VGA BIOS (loaded via QEMU) to store video modes (`0x0049`) and column count (`0x004A`). -* **Custom BDA (`0050:0000`)**: Defined by `BDA_DATA_SEG`. Stores driver states: +* **Custom BDA (`0050:0000`)**: Defined by `BDA_CUSTOM_SEG`. Stores driver states: * **Mouse**: Input buffer, status, coordinates, background buffer (for cursor). * **Gfx**: Text cursor position, attributes. - * **GUI RAM**: Segment `0x0060` (Physical `0x00600`). - * **Layout**: Located in low memory (`0x0060`) to avoid any collision with the Stack (`0x0800`). + * **GUI RAM**: Segment `0x0063` (Physical `0x00630`). + * **Layout**: Located in low memory to avoid any collision with the Stack (`0x0800`). #### Stack * **Stack**: Grows downwards from physical address `0xFFFE` (16-bit aligned) of the "Stack Segment" defined by `STACK_SEG`. @@ -71,11 +73,13 @@ Le processeur démarre en mode réel, adressant 1 Mo de mémoire. | :--- | :--- | :--- | :--- | :--- | :--- | | **`0x00000`** | **`0x003FF`** | 1 KB | **IVT** (Interrupt Vector Table) | `0x0000` | `memory.asm` | | **`0x00400`** | **`0x004FF`** | 256 B | **BDA** (BIOS Data Area) Standard | `0x0040` | `memory.asm` | -| **`0x00500`** | **`0x005FF`** | 256 B | **Custom BDA** (Driver Data) | `0x0050` | `memory.asm` | -| **`0x00600`** | **`0x00AFF`** | 1.25 KB | **GUI RAM** (Widget Allocation) | `0x0060` | `gui/lib.asm` | -| **`0x00B00`** | **`0x07FFF`** | 29 KB | **Free** (Low Memory) | | | +| **`0x00500`** | **`0x006FF`** | ~512 B | **Custom BDA** (Driver Data) | `0x0050` | | +| **`0x00700`** | **`0x00A6F`** | ~1792 B | **GUI RAM** (Widget Allocation) | **`0x0070`** | `gui/lib-api.asm` | +| **`0x00A70`** | **`0x07FFF`** | ~ 29 KB | **Free** (Low Memory) | | | | **`0x08000`** | **`0x17FFF`** | 64 KB | **Stack** (Grows downwards) | `0x0800` | `boot.asm` | -| **`0x18000`** | **`0x9FFFF`** | 544 KB | **Free** (Conventional RAM) | | | +| **`0x18000`** | **`0x1FFFF`** | 32 KB | **Libre** | | | +| **`0x20000`** | **`0x2FFFF`** | 64 KB | **Heap** (Allocation Dynamique) | `0x2000` | `memory.asm` | +| **`0x30000`** | **`0x9FFFF`** | 448 KB | **Libre** (RAM Conventionnelle) | | | | **`0xA0000`** | **`0xAFFFF`** | 64 KB | **VGA RAM** (Graphics Modes) | `0xA000` | `Hardware` | | **`0xB0000`** | **`0xB7FFF`** | 32 KB | **MDA RAM** (Monochrome Text) | `0xB000` | `Hardware` | | **`0xB8000`** | **`0xBFFFF`** | 32 KB | **VRAM** (CGA / MCGA) | `0xB800` | `generic.asm` | @@ -96,11 +100,11 @@ Le processeur démarre en mode réel, adressant 1 Mo de mémoire. Le projet sépare la BDA standard IBM de ses propres variables pour éviter les conflits avec le BIOS VGA chargé en `0xC000`. * **BDA Standard (`0040:0000`)** : Utilisée principalement par le BIOS VGA (chargé via QEMU) pour stocker les modes vidéo (`0x0049`) et le nombre de colonnes (`0x004A`). -* **Custom BDA (`0050:0000`)** : Définie par `BDA_DATA_SEG`. Stocke l'état des drivers : +* **Custom BDA (`0050:0000`)** : Définie par `BDA_CUSTOM_SEG`. Stocke l'état des drivers : * **Souris** : Buffer d'entrée, état, coordonnées, buffer de sauvegarde du fond (pour le curseur). * **Gfx** : Position du curseur texte, attributs. - * **GUI RAM** : Segment `0x0060`. - * **Organisation** : Située en mémoire basse (`0x0060`) pour éviter toute collision avec la Pile (`0x0800`). + * **GUI RAM** : Segment `0x0063` (Physique `0x00630`). + * **Organisation** : Située en mémoire basse pour éviter toute collision avec la Pile (`0x0800`). #### Stack * **Stack** : Grandit vers le bas depuis l'adresse physique `0xFFFE` (Alignement sur 16 bits) du "stack Segment" défini par `STACK_SEG`. diff --git a/src/boot-ok.asm b/src/boot-ok.asm new file mode 100644 index 0000000..9630900 --- /dev/null +++ b/src/boot-ok.asm @@ -0,0 +1,274 @@ +; ============================================================================= +; Project : Custom BIOS / ROM +; File : boot.asm +; Author : frater +; +; License : GNU General Public License v3.0 or later (GPL-3.0+) +; +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . +; +; ============================================================================= + + bits 16 +; --------------------------------------------------------------------------- +; +; configuration du bios +; +; --------------------------------------------------------------------------- + +; initial stack +%define STACK_SEG 0x0800 ; segment de base +%define GFX_DRIVERS 'CGA' + +section .text + bits 16 + +%include "./common/chartable.asm" +%include "./common/cursor.asm" +%include "./common/patterns.asm" +%include "./common/generic.asm" +%include "./common/string.asm" + +; definition du BDA +%include "./common/bda.asm" + +; drivers +%if GFX_DRIVERS == 'VGA' + %include "./drivers/gfx_vga.asm" +%else + ; default drivers + %include "./drivers/gfx_cgam.asm" +%endif + +%include "./drivers/mouse_ps2.asm" +%include "./drivers/keyboard_ps2.asm" + +%include "./common/debug_gfx.asm" + +; GUI +%include "./gui/lib-api.asm" + +; --- Données texte --- +str_quit db "Quitter", 0 +str_hello db "Hello", 0 +str_option1 db "option 1", 0 +str_option2 db "option 2", 0 +str_option3 db "option 3", 0 + +entrycode: + cli + mov ax, STACK_SEG ; creation du stack par défaut + mov ss, ax + mov sp, 0xFFFE ; haut du segment (64ko de stack), mot-aligné + cld + + call ivt_setup ; configuration d'une table d'interruption "dummy" + call bda_setup ; initialisation du BDA + + ISADBG ISA_GREEN, 0x01 + + ; Install IRQ 0 : timer_isr + mov ax,cs + mov dx,ax + mov bx,timer_isr + mov ax,i8259_MASTER_INT + + call ivt_setvector + + ISADBG ISA_GREEN, 0x02 + + ; initialisation des PIC 8259A + call pic_init + + ISADBG ISA_GREEN, 0x04 + + ; load Roms + call setup_load_rom + + ISADBG ISA_GREEN, 0x08 + + ; on vérifie que le BIOS VGA a installé une INT 10h + call setup_check_vga + + ISADBG ISA_GREEN, 0x10 + + ; enable IRQ 0 + mov ah,IRQ_ENABLED + mov al,0 + call pic_set_irq_mask + + call kbd_init + sti + + DEBUG 0xFADE + ISADBG ISA_GREEN, 0x20 + + ; on active le mode graphique + GFX INIT + ISADBG ISA_GREEN, 0xFF + + ; call mouse_reset + call mouse_init + + GFX MOUSE_MOVE + GFX MOUSE_SHOW + + ISADBG ISA_RED, 0x81 + + xor ax,ax + + .loops: + call main_loop + + nop + jmp .loops + +; --- Callbacks (Fonctions appelées par le moteur) --- +on_click_quit: + hlt + jmp on_click_quit + ret + +on_click_hello: + ret + +%define .oldval word [bp-2] +%define .my_slider word [bp-4] +%define .value word [bp-6] +main_loop: + push bp + mov bp, sp + sub sp, 6 + + push cs + pop ds + + DEBUG 1 + ISADBG ISA_LEFT, 1 + + ; Init du système GUI + call gui_init_system + DEBUG 2 + ISADBG ISA_LEFT, 2 + + ; --- CRÉATION DYNAMIQUE DES BOUTONS --- + + ; Créer Bouton 1 "QUITTER" + GUI OBJ_CREATE, OBJ_TYPE_BUTTON_ROUNDED, 10, 10, 80, 16 + GUI OBJ_SET_TEXT, ax, cs, str_quit + ; Créer Bouton 2 "HELLO" + GUI OBJ_CREATE, OBJ_TYPE_BUTTON_ROUNDED, 100, 50, 80, 16 + GUI OBJ_SET_TEXT, ax, cs, str_hello + + ; Créer 3 checkbox "option" + GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50, 100, 15 + GUI OBJ_SET_TEXT, ax, cs, str_option1 + + GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50+16, 100, 15 + GUI OBJ_SET_TEXT, ax, cs, str_option2 + + GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50+16*2, 100, 15 + GUI OBJ_SET_TEXT, ax, cs, str_option3 + + DEBUG 3 + ISADBG ISA_LEFT, 3 + + ; Créer Slider (Drag) + GUI OBJ_CREATE, OBJ_TYPE_SLIDER, 10, 100, 150, 12 + GUI OBJ_SET_MODE, ax, SLIDER_HORIZONTAL + GUI OBJ_SLIDER_SET_ATTR, ax, 10, 140, 10, 15 + + GUI OBJ_CREATE, OBJ_TYPE_SLIDER, 400, 10, 16, 150 + mov .my_slider, ax + + GUI OBJ_SET_MODE, .my_slider, SLIDER_VERTICAL + GUI OBJ_SLIDER_SET_ATTR, .my_slider, 0, 31, 0, 12 + + mov .oldval, 0x1256 + mov .value, 0xFADE + + DEBUG 4 + ISADBG ISA_LEFT, 4 + + .loop: + call gui_process_all + GUI OBJ_GET_VAL, .my_slider + mov .value, ax + + cmp ax,.oldval + je .loop + + ; debug + mov .oldval, ax + GFX RECTANGLE_FILL,0,148,50,166, PATTERN_WHITE + GFX GOTOXY, 8, 150 + + mov ax, .value + call print_word_hex + ; end debug + + ; change palette... + ;and ax, 0x00FF + ;mov bh, 0x00 + ;mov bl, al + ;mov ah, 0x0b + ;mov al, 0x00 + ;int 0x10 + + mov dx, CRTC_COLOR_DATA + and ax, 0x001F + out dx, ax + + jmp .loop + leave + ret + +; ----------------------------------------------------------- +; timer ISR (IRQ -> INT) +; ----------------------------------------------------------- +timer_isr: + push ax + + push fs + mov ax,BDA_CUSTOM_SEG + mov fs,ax +; exemple de fonctionnement: +; inc byte [fs:BDA_TIMER] + + mov al, PIC_EOI ; EOI master + out i8259_MASTER_CMD, al + pop fs + + pop ax + iret + +; ------------------------------------------------------------------ +; Padding jusqu'au reset vector +; ------------------------------------------------------------------ +times 0xFFF0 - ($ - $$) db 0xFF + +; ------------------------------------------------------------------ +; RESET VECTOR (exécuté par le CPU) +; ------------------------------------------------------------------ +section .resetvect +bits 16 +global reset_vector + +reset_vector: + ; code minimal au reset + jmp 0xF000:entrycode + +builddate: + db __DATE__ + times 16-($-$$) db 0 ; le stub tient dans 16 octets (ou moins) diff --git a/src/boot.asm b/src/boot.asm index 2a4f1d6..3fb0629 100644 --- a/src/boot.asm +++ b/src/boot.asm @@ -29,13 +29,9 @@ ; initial stack %define STACK_SEG 0x0800 ; segment de base +%define GFX_DRIVERS 'VGA' -;section .text -; bits 16 -; -; db 'EXTRA CODE Section',0 -; -; times 0xFFFF - ($ - $$) db 0xFF +%define DEBUGER_ENABLED section .text bits 16 @@ -50,15 +46,20 @@ section .text %include "./common/bda.asm" ; drivers -%include "./drivers/gfx_cgam.asm" +%if GFX_DRIVERS == 'VGA' + %include "./drivers/gfx_vga.asm" +%else + ; default drivers + %include "./drivers/gfx_cgam.asm" +%endif + %include "./drivers/mouse_ps2.asm" %include "./drivers/keyboard_ps2.asm" -%include "./common/debug_cga.asm" +%include "./common/debug_gfx.asm" ; GUI -%include "./gui/lib.asm" -%include "./gui/draw.asm" +; %include "./gui/lib-api.asm" ; --- Données texte --- str_quit db "Quitter", 0 @@ -86,24 +87,12 @@ entrycode: mov ax,i8259_MASTER_INT call ivt_setvector - - ISADBG ISA_GREEN, 2 - ; initialisation des PIC 8259A call pic_init - - ISADBG ISA_GREEN, 4 - ; load Roms call setup_load_rom - - ISADBG ISA_GREEN, 8 - ; on vérifie que le BIOS VGA a installé une INT 10h call setup_check_vga - - ISADBG ISA_GREEN, 16 - ; enable IRQ 0 mov ah,IRQ_ENABLED mov al,0 @@ -112,19 +101,18 @@ entrycode: call kbd_init sti - DEBUG 0xFADE - ISADBG ISA_GREEN, 32 ; on active le mode graphique GFX INIT - call mouse_init + call mouse_reset + + ; call mouse_init GFX MOUSE_MOVE ISADBG ISA_RED, 0x80 GFX MOUSE_SHOW - ISADBG ISA_RED, 0x81 .loops: @@ -155,71 +143,14 @@ main_loop: ISADBG ISA_LEFT, 1 ; Init du système GUI - call gui_init_system +; call gui_init_system DEBUG 2 ISADBG ISA_LEFT, 2 - ; --- CRÉATION DYNAMIQUE DES BOUTONS --- - - ; Créer Bouton 1 "QUITTER" - GUI OBJ_CREATE, OBJ_TYPE_BUTTON_ROUNDED, 10, 10, 80, 16 - GUI OBJ_SET_TEXT, ax, cs, str_quit - ; Créer Bouton 2 "HELLO" - GUI OBJ_CREATE, OBJ_TYPE_BUTTON_ROUNDED, 100, 50, 80, 16 - GUI OBJ_SET_TEXT, ax, cs, str_hello - ; Créer checkbox 3 "option 1" - GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50, 100, 15 - GUI OBJ_SET_TEXT, ax, cs, str_option1 - - GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50+16, 100, 15 - GUI OBJ_SET_TEXT, ax, cs, str_option2 - - GUI OBJ_CREATE, OBJ_TYPE_CHECKBOX, 200, 50+16*2, 100, 15 - GUI OBJ_SET_TEXT, ax, cs, str_option3 - - DEBUG 3 - ISADBG ISA_LEFT, 3 - - ; Créer Slider (Drag) - GUI OBJ_CREATE, OBJ_TYPE_SLIDER, 10, 100, 150, 12 - GUI OBJ_SET_MODE, ax, SLIDER_HORIZONTAL - GUI OBJ_SLIDER_SET_ATTR, ax, 10, 140, 10, 15 - - GUI OBJ_CREATE, OBJ_TYPE_SLIDER, 400, 10, 16, 150 - mov .my_slider, ax - - GUI OBJ_SET_MODE, .my_slider, SLIDER_VERTICAL - GUI OBJ_SLIDER_SET_ATTR, .my_slider, 0, 15, 15, 12 - - mov .oldval, 0x1256 - mov .value, 0xFADE - - DEBUG 4 - ISADBG ISA_LEFT, 4 - - .loop: - call gui_process_all - GUI OBJ_GET_VAL, .my_slider - mov .value, ax - - cmp ax,.oldval - je .loop - - ; debug - mov .oldval, ax - GFX RECTANGLE_FILL,0,148,50,166, PATTERN_WHITE - GFX GOTOXY, 8, 150 - - mov ax, .value - call print_word_hex - ; end debug - - mov dx, 0x3d9 - mov ax, .value - and ax, 0x000F - out dx, al + .loop: +; call gui_process_all jmp .loop leave @@ -232,7 +163,7 @@ timer_isr: push ax push fs - mov ax,BDA_DATA_SEG + mov ax,BDA_CUSTOM_SEG mov fs,ax ; exemple de fonctionnement: ; inc byte [fs:BDA_TIMER] diff --git a/src/common/bda.asm b/src/common/bda.asm index f4d18f2..703a306 100644 --- a/src/common/bda.asm +++ b/src/common/bda.asm @@ -24,11 +24,9 @@ ; https://wiki.nox-rhea.org/back2root/ibm-pc-ms-dos/hardware/informations/bios_data_area ; -%define BDA_SEGMENT 0x0040 ; segment BDA - -; custom vars -%define BDA_INFO_MEM_SIZE 0x0014 ; Memory size in Kbytes -%define BDA_INFO_MEM_SEG BDA_INFO_MEM_SIZE+2 ; highest Memory Segment +%define BDA_SEGMENT 0x0040 ; segment BDA (historically) +%define BDA_CUSTOM_SEG 0x0050 ; custom data (mouse, gfx cursor, etc..) +%define BDA_GUI_WIDGET 0x0070 ; Segment de données UI (Safe: après Stack, avant Heap) ; video related information (compatible with VGA bios) %define BDA_VIDEO_CURR_MODE 0x0049 @@ -38,7 +36,8 @@ ; ; information relative à la souris ; -%define BDA_DATA_SEG 0x0050 + +%define BDA_BitPP 4 %define BKG_DWORDS_PER_LINE 1 ; 1 dword stocké par ligne %define BKG_LINES 16 @@ -63,7 +62,8 @@ struc mouse .cur_ofs resw 1 ; .bkg_saved resb 1 ; background saved alignb 4 ; alignement 4 bytes - .bkg_buffer resd 16 ; buffer for saved background + ; buffer for saved background + .bkg_buffer resd 16*BDA_BitPP endstruc struc gfx @@ -86,7 +86,7 @@ bda_setup: pusha push ds - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov es, ax mov ax, 0x5F diff --git a/src/common/debug_cga.asm b/src/common/debug_gfx.asm similarity index 97% rename from src/common/debug_cga.asm rename to src/common/debug_gfx.asm index 3e40c5e..29bfe4a 100644 --- a/src/common/debug_cga.asm +++ b/src/common/debug_gfx.asm @@ -42,8 +42,7 @@ dump_ram_words: call print_word_hex ; Affiche AX sous forme "XXXX" ; (Optionnel) Ajouter un espace entre chaque mot pour la lisibilité - mov al, ' ' - call cga_putc + GFX PUTCH, ' ' pop si ; Restaure SI pop cx ; Restaure CX @@ -77,9 +76,7 @@ print_word_hex: xor bx, bx mov bl, al - push bx - call cga_putc - add sp, 2 + GFX PUTCH, bx loop .next_digit ; Répète 4 fois popa diff --git a/src/common/generic.asm b/src/common/generic.asm index aff6845..374bb4c 100644 --- a/src/common/generic.asm +++ b/src/common/generic.asm @@ -20,16 +20,12 @@ ; ; ============================================================================= -%define DISABLE_DEBUGER - -%ifndef DISABLE_DEBUGER - +%ifdef DEBUGER_ENABLED %macro DEBUG 1 GFX GOTOXY, 0, 0 mov ax, %1 call print_word_hex %endmacro - ; ; Debugger for 86Box ; @@ -111,6 +107,26 @@ %define IRQ_ENABLED 0x00 %define IRQ_DISABLED 0x01 +; --------------------------------------------------------------------------- +; CGA/MDA Controler +; --------------------------------------------------------------------------- +; +; MDA 6845 +%define CRTC_6845_MONO 0x03b4 +%define CRTC_6845_MONO_REGISTER 0x03b5 +; +; CGA 6845 +%define CRTC_6845_COLOR 0x03d4 +%define CRTC_6845_COLOR_REGISTER 0x03d4 +%define CRTC_COLOR_REGISTER 0x03d5 + +%define CRTC_COLOR_CTRL 0x03d8 +%define CRTC_COLOR_DATA 0x03d9 + +%define EGAVGA_CONTROLLER 0x03ce + +%define VGA_SEQUENCER 0x03c4 + ; --------------------------------------------------------------------------- ; Détection les ROM supplementaires ; Teste la RAM de 0xC000 jusqu’à 0xE000, par pas de 2KB. diff --git a/src/common/patterns.asm b/src/common/patterns.asm index 26440a2..c2655d6 100644 --- a/src/common/patterns.asm +++ b/src/common/patterns.asm @@ -13,9 +13,16 @@ align 8 pattern_8x8: - dq 0x0000000000000000 ; pattern_black (Tout à 0 = Noir) - dq 0x2200880022008800 ; pattern_gray_dark (Majorité de 0) - dq 0x2288228822882288 ; pattern_gray_mid - dq 0xAA55AA55AA55AA55 ; pattern_gray_light (50/50) - dq 0x77DD77DD77DD77DD ; pattern_white_light (Majorité de 1 = Clair) - dq 0xFFFFFFFFFFFFFFFF ; pattern_white (Tout à 1 = Blanc) + dq 0x0000000000000000 ; 0 : pattern_black (Tout à 0 = Noir) + dq 0x2200880022008800 ; 1 : pattern_gray_dark (Majorité de 0) + dq 0x2288228822882288 ; 2 : pattern_gray_mid + dq 0xAA55AA55AA55AA55 ; 3 : pattern_gray_light (50/50) + dq 0x77DD77DD77DD77DD ; 4 : pattern_white_light (Majorité de 1 = Clair) + dq 0xFFFFFFFFFFFFFFFF ; 5 : pattern_white (Tout à 1 = Blanc) + + +%macro PATTERN_PTR 1 + mov ax, cs + mov ds, ax + lea esi, [pattern_8x8 + (%1 * 8)] +%endmacro \ No newline at end of file diff --git a/src/drivers/gfx_cgam.asm b/src/drivers/gfx_cgam.asm index e932cbe..e2cfb37 100644 --- a/src/drivers/gfx_cgam.asm +++ b/src/drivers/gfx_cgam.asm @@ -31,7 +31,6 @@ %define CGA_STRIDE 80 %define CGA_ODD_BANK 0x2000 - ; ; bit : descr ; 0 : text color : 0=black, 1=white @@ -78,6 +77,7 @@ %define MOUSE_HIDE 11 %define MOUSE_SHOW 12 %define MOUSE_MOVE 13 +%define MOUSE_DRAW 14 ; ------------------------------------------------------------ ; COMMENTAIRE SUR LA MÉTHODE D'APPEL @@ -105,6 +105,7 @@ graph_driver: dw cga_mouse_hide ; déplacement du curseur dw cga_mouse_show ; déplacement du curseur dw cga_mouse_cursor_move ; déplacement du curseur + dw cga_cursor_draw ; ------------------------------------------------------------ ; initialise le mode graphique (via l'int 10h) @@ -112,7 +113,7 @@ graph_driver: ; ce mode est entrelacé, un bit/pixel, 8 pixels par octet ; ------------------------------------------------------------ cga_init: - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax ; init graphics mode @@ -180,7 +181,7 @@ cga_set_writemode: push fs push ax - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov fs,ax mov ax, .mode @@ -211,7 +212,7 @@ cga_set_charpos: pusha push fs - mov ax,BDA_DATA_SEG + mov ax,BDA_CUSTOM_SEG mov fs,ax ; store x,y en pixel @@ -314,7 +315,7 @@ cga_putc: mov bx, VIDEO_SEG mov es, bx - mov bx, BDA_DATA_SEG + mov bx, BDA_CUSTOM_SEG mov fs, bx mov ax, .car @@ -1267,7 +1268,7 @@ cga_mouse_hide: pusha ; Sauvegarder TOUS les registres 32-bits push ds - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax ; Décrémenter le compteur @@ -1295,7 +1296,7 @@ cga_mouse_show: pusha push ds - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax ; Incrémenter le compteur @@ -1327,7 +1328,7 @@ cga_mouse_cursor_move: push es ; move Data Segment - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax cmp byte [BDA_MOUSE + mouse.cur_counter], 0 @@ -1437,10 +1438,7 @@ cga_cursor_restorebg: ret ; ============================================================ -; gfx_cursor_draw_rm16_i386_self -; Entrée: -; DS = BDA_DATA_SEG -; Sortie: rien +; cga_cursor_draw ; Détruit: registres sauvegardés/restaurés (PUSHA/POPA) ; ============================================================ %define .height word [bp-2] @@ -1456,24 +1454,23 @@ cga_cursor_draw: push gs cld ; Sécurité : Direction avant - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax mov ax, VIDEO_SEG mov es, ax ; --- CLIPPING VERTICAL --- mov dx, [ds:BDA_MOUSE + mouse.y] - cmp dx, 200 + mov bx, GFX_HEIGHT + cmp dx, bx jae .exit_total mov ax, 16 - mov bx, 200 sub bx, dx ; 200-y cmp ax, bx jbe .y_ok ; y<= 200-16 mov ax, bx - .y_ok: mov .height, ax diff --git a/src/drivers/gfx_vga.asm b/src/drivers/gfx_vga.asm new file mode 100644 index 0000000..b7d62eb --- /dev/null +++ b/src/drivers/gfx_vga.asm @@ -0,0 +1,619 @@ +; ============================================================================= +; Project : Custom BIOS / ROM +; File : gfx_vga.asm +; Author : frater +; +; License : GNU General Public License v3.0 or later (GPL-3.0+) +; +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . +; +; ============================================================================= + +; +; graphics drivers pour carte video/mode CGA-Mono (640x200x2) +; +%define VIDEO_SEG 0A000h + +%define GFX_MODE 0x12 ; VGA HiRes (640x480x16) +%define GFX_WIDTH 640 +%define GFX_HEIGHT 480 +; +; bit : descr +; 0 : text color : 0=black, 1=white +; 1 : transparent : 1=apply background attribut +; +%define GFX_TXT_WHITE_TRANSPARENT 00000000b +%define GFX_TXT_BLACK_TRANSPARENT 00000001b +%define GFX_TXT_WHITE 00000010b +%define GFX_TXT_BLACK 00000011b + +%macro GFX 1-* + ; %1 est l'index de la fonction + ; On itère sur les arguments suivants en sens inverse (Convention C) + + %rep %0 - 1 ; Répéter pour (Nombre d'args - 1) + %rotate -1 ; Prend le dernier argument + push %1 ; L'empile + %endrep + + %rotate -1 ; On revient au premier argument (l'index de fonction) + call word [cs:graph_driver + ((%1)*2)] + + ; Nettoyage de la pile (Convention CDECL: l'appelant nettoie) + ; Chaque argument = 2 octets (1 word). + add sp, (%0 - 1) * 2 +%endmacro + +; ------------------------------------------------------------ +; TABLE DE SAUT (VECTEURS API) +; Cette table doit être située au début du driver pour être +; accessible par la GUI à des offsets fixes. +; ------------------------------------------------------------ +%define INIT 0 +%define PUTPIXEL 1 +%define GETPIXEL 2 +%define GOTOXY 3 +%define TXT_MODE 4 +%define PUTCH 5 +%define WRITE 6 +%define LINE 7 +%define RECTANGLE 8 +%define RECTANGLE_FILL 9 +%define RECTANGLE_ROUND 10 +%define MOUSE_HIDE 11 +%define MOUSE_SHOW 12 +%define MOUSE_MOVE 13 +%define MOUSE_DRAW 14 + +; ------------------------------------------------------------ +; COMMENTAIRE SUR LA MÉTHODE D'APPEL +; +; GFX FUNCTION, Arg1, Arg2, Arg3 +; +; GFX GFX_PUTPIXEL, 320, 100, 1 +; +; Si vous changez le code du driver, tant que la table au début +; ne change pas d'ordre, la GUI n'a pas besoin d'être recompilée. +; ------------------------------------------------------------ +align 2 +graph_driver: + dw vga_init ; init de la carte graphique + dw vga_putpixel ; dessin d'un pixel + dw vga_none ; lecture d'un pixel + dw vga_none ; gotoxy + dw vga_none ; mode texte + dw vga_none ; dessin d'un caractère + dw vga_none ; dessin d'une chaine de caractère + dw vga_none ; dessin d'une ligne (Bresenham) avec décision horizontale/verticale + dw vga_none ; dessin d'un rectangle + dw vga_none ; dessin d'un rectangle plein + dw vga_none ; dessin d'un rectangle arrondi + dw vga_mouse_hide ; cache la souris + dw vga_mouse_show ; montre la souris + dw vga_mouse_cursor_move ; déplacement du curseur + dw vga_cursor_draw + +; ------------------------------------------------------------ +; dummy function +; +; cette fonction ne sert a rien, juste a "occuper" l'espace +; dans la table pour fonction qui n'existent pas +; ------------------------------------------------------------ +vga_none: + ret + +; ------------------------------------------------------------ +; initialise le mode graphique (via l'int 10h) +; +; ce mode est entrelacé, un bit/pixel, 8 pixels par octet +; ------------------------------------------------------------ +vga_init: + ; init graphics mode + mov ah, 0x00 ; AH=00h set video mode + mov al, GFX_MODE + int 0x10 + + ; dessine un background "check-board" + ; Les patterns sont dans le segment de code (CS) + push cs + pop ds + + PATTERN_PTR PATTERN_GRAY_LIGHT + mov bl, 15 + call vga_background + ISADBG ISA_GREEN, 0x88 + ret + +; ------------------------------------------------------------ +; vga_calc_addr +; Entrée: +; CX = X (0-639) +; DX = Y (0-479) +; Sortie: +; DI = Offset dans le segment A000h +; ------------------------------------------------------------ +vga_calc_addr: + push ax + push dx + + ; Calcul de Y * 80 + ; 80 = 64 + 16 (soit Y<<6 + Y<<4) pour éviter une multiplication lente + mov ax, dx ; AX = Y + shl ax, 4 ; AX = Y * 16 + mov di, ax ; DI = Y * 16 + shl ax, 2 ; AX = (Y * 16) * 4 = Y * 64 + add di, ax ; DI = (Y * 64) + (Y * 16) = Y * 80 + + ; Ajout de X / 8 + shr cx, 3 ; CX = X / 8 (octet horizontal) + add di, cx ; DI = (Y * 80) + (X / 8) + + pop dx + pop ax + ret + +; Entrée: ESI = Pointeur vers le tableau de 8 octets (pattern 8x8) +; BL = Couleur de premier plan (0-15) +vga_background: +; pushad + + ; Configuration VGA pour le remplissage de masse + mov dx, VGA_SEQUENCER ; Sequencer + mov ax, 0F02h ; Map Mask (Index 2) = 0Fh (Tous les plans) + out dx, ax + + ; Graphics Controller + mov dx, EGAVGA_CONTROLLER + mov ax, 0305h ; Mode Register (Index 5) = Mode 3 + out dx, ax + + mov al, 00h ; Set/Reset (Index 0) = Couleur + mov ah, bl + out dx, ax + + ; Initialisation mémoire + mov ax, VIDEO_SEG + mov es, ax + xor edi, edi ; ES:EDI = Début mémoire vidéo + movzx esi, si ; Nettoyer ESI (garder SI) pour l'adressage + + ; Boucle principale (480 lignes) + xor edx, edx ; EDX servira d'index pour le pattern (0-7) + mov ecx, 480 + + .line_loop: + mov al, [esi + edx] ; Charger l'octet du pattern pour la ligne actuelle + ; Répliquer l'octet AL dans EAX (ex: 0xAA -> 0xAAAAAAAA) pour le 32-bit + mov ah, al ; copy byte 0 -> byte 1 + mov bx, ax ; préserve word + shl eax, 16 ; shift low word -> hi word + mov ax, bx ; EAX contient maintenant 4 fois le pattern de 8 pixels + + mov bp, 20 ; 80 octets / 4 (32-bit) = 20 itérations par ligne + .row_loop: + mov bl, [es:di] ; LATCH LOAD : Lecture indispensable en Mode 3 + stosd + ;mov [es:edi], eax ; Écrit 32 pixels d'un coup avec le pattern + ;add edi, 4 + dec bp + jne .row_loop + + ; Passer à la ligne suivante du pattern (modulo 8) + inc edx + and edx, 7 ; Si EDX=8, revient à 0 + loop .line_loop + + ; Cleanup + mov dx, EGAVGA_CONTROLLER + mov ax, 0005h ; Reset Write Mode 0 + out dx, ax +; popad + ret + +; Entrée: AX = X (0-639), BX = Y (0-479), CL = Couleur (0-15) +%define .x word [bp+4] +%define .y word [bp+6] +%define .color byte [bp+8] +vga_putpixel: + push bp + mov bp, sp + pusha + + mov bx, .y + mov ax, .x + mov cl, .color + ; Calcul de l'offset (Y * 80 + X/8) + + imul di, bx, 80 ; DI = Y * 80 + mov bx, ax ; Sauvegarde X + shr ax, 3 ; AX = X / 8 + add di, ax ; DI = Offset final + + ; Calcul du masque de bit (7 - (X % 8)) + and bx, 7 ; BX = X % 8 + mov ah, 80h ; Bit 7 à 1 + shr ah, cl ; Décale pour pointer le bon pixel (cl = bx ici) + ; Note: en pratique on utilise souvent une table de pré-calcul pour shr ah, bl + + ; Programmation du Graphics Controller + mov dx, EGAVGA_CONTROLLER + + ; Sélection du Bit Mask (Index 8) + mov al, 08h + out dx, ax ; AH contient le masque calculé + + ; Sélection du Set/Reset (Couleur, Index 0) + mov ax, 0000h + mov al, 00h + mov ah, cl ; Couleur + out dx, ax + + ; Enable Set/Reset (On active les 4 plans, Index 1) + mov ax, 0F01h + out dx, ax + + ; 4. Écriture (Nécessite une lecture préalable pour charger les Latches) + mov ax, VIDEO_SEG + mov es, ax + mov al, [es:di] ; Lecture bidon pour charger les verrous (latches) + mov [es:di], al ; L'écriture applique la couleur via le matériel + + ; Reset des registres pour ne pas casser le reste du dessin + mov ax, 0FF08h + out dx, ax + mov ax, 0001h + out dx, ax + + popa + leave + ret +; clean defs +%undef .x +%undef .y +%undef .color + + +; ------------------------------------------------------------ +; GESTION DU CURSEUR +; ------------------------------------------------------------ +; +; ------------------------------------------------------------ +; gère la demande d'effacement du curseur souris +; +; ------------------------------------------------------------ +vga_mouse_hide: + pushf ; Sauver l'état des flags (interrupts) + cli ; Désactiver les interruptions (CRITIQUE) + pusha ; Sauvegarder TOUS les registres 32-bits + push ds + + mov ax, BDA_CUSTOM_SEG + mov ds, ax + + ; Décrémenter le compteur + dec byte [BDA_MOUSE + mouse.cur_counter] + + ; Vérifier si on vient juste de passer en mode caché (c-à-d on est à -1) + cmp byte [BDA_MOUSE + mouse.cur_counter], -1 + jne .skip_restore ; Si on est à -2, -3... elle est déjà cachée + + call vga_cursor_restorebg + + .skip_restore: + pop ds + popa + popf ; Restaure les interruptions (STI si elles étaient là) + ret + +; ------------------------------------------------------------ +; gère la demande d'affichage du curseur souris +; +; ------------------------------------------------------------ +vga_mouse_show: + pushf + cli + pusha + push ds + + mov ax, BDA_CUSTOM_SEG + mov ds, ax + + ; Incrémenter le compteur + inc byte [BDA_MOUSE + mouse.cur_counter] + + ; Vérifier si on est revenu à 0 (Visible) + cmp byte [BDA_MOUSE + mouse.cur_counter], 0 + jne .skip_draw ; Si on est encore à -1, -2... on reste caché + + ; C'est la transition Caché -> Visible : On affiche le curseur + ; IMPORTANT : On sauve le fond ACTUEL (qui a peut-être changé pendant le hide) + call vga_cursor_savebg + call vga_cursor_draw + + .skip_draw: + pop ds + popa + popf ; restore également le flag d'interruption + ret + + +; ------------------------------------------------------------ +; gère le déplacement du curseur souris +; +; ------------------------------------------------------------ +vga_mouse_cursor_move: + pusha + push ds + push es + + ; BDA Data Segment + mov ax, BDA_CUSTOM_SEG + mov ds, ax + + cmp byte [BDA_MOUSE + mouse.cur_counter], 0 + jl .done ; Si < 0, on ne dessine rien ! + + cmp byte [BDA_MOUSE + mouse.cur_drawing],0 + jne .done + + mov byte [BDA_MOUSE + mouse.cur_drawing],1 + + call vga_cursor_restorebg + call vga_cursor_savebg + call vga_cursor_draw + mov byte [BDA_MOUSE + mouse.cur_drawing],0 + .done: + pop es + pop ds + popa + ret + +; Buffer requis : 192 octets (16 lignes * 3 octets * 4 plans) +; ATTENTION : Vérifiez que mouse.bkg_buffer dans bda.asm est assez grand ! +vga_cursor_savebg: + cmp byte [BDA_MOUSE + mouse.bkg_saved], 0 + jne .done + + push es + mov ax, VIDEO_SEG + mov es, ax + + ; Calculer l'adresse de départ (y * 80 + x / 8) + mov cx, [BDA_MOUSE + mouse.x] + mov dx, [BDA_MOUSE + mouse.y] + call vga_calc_addr ; Doit retourner DI = offset VRAM + mov [BDA_MOUSE + mouse.cur_addr_start], di + + lea si, [BDA_MOUSE + mouse.bkg_buffer] + + mov dx, EGAVGA_CONTROLLER ; Graphics Controller Port + mov al, 0x04 ; Read Plane Select Register + out dx, al + inc dx ; Point sur Data Port (0x03CF) + + xor bl, bl ; BL = Index du plan (0 à 3) + .plan_loop: + mov al, bl + out dx, al ; Sélectionner le plan à lire + + push di ; Sauver l'adresse de départ du curseur + mov cx, 16 ; 16 lignes + .row_loop: + mov ax, [es:di] ; Lit 16 pixels (2 octets) + mov [ds:si], ax + mov al, [es:di+2] ; Lit le 3eme octet (pour le shift) + mov [ds:si+2], al + add si, 3 + add di, 80 ; Ligne suivante (VGA linéaire) + loop .row_loop + + pop di ; Revenir en haut pour le plan suivant + inc bl + cmp bl, 4 + jne .plan_loop + + ; Reset Read Map Select to 0 (Nettoyage) + mov dx, 0x3CE + mov ax, 0x0004 + out dx, ax + + pop es + mov byte [BDA_MOUSE + mouse.bkg_saved], 1 + .done: + ret + +vga_cursor_restorebg: + cmp byte [BDA_MOUSE + mouse.bkg_saved], 0 + je .done + + push es + mov ax, VIDEO_SEG + mov es, ax + + mov di, [BDA_MOUSE + mouse.cur_addr_start] + lea si, [BDA_MOUSE + mouse.bkg_buffer] + + ; Sécurité : S'assurer que ES pointe bien vers la vidéo pour le restore + mov ax, VIDEO_SEG + mov es, ax + + ; Sécurité : Réinitialiser le contrôleur graphique pour l'écriture CPU brute + mov dx, EGAVGA_CONTROLLER + mov ax, 0x0005 ; Mode 0 + out dx, ax + mov ax, 0x0001 ; Enable Set/Reset = 0 (Important !) + out dx, ax + mov ax, 0xFF08 ; Bit Mask = 0xFF + out dx, ax + mov ax, 0x0003 ; Function = Replace + out dx, ax + + mov dx, VGA_SEQUENCER ; Sequencer Port + mov al, 0x02 ; Map Mask Register + out dx, al + inc dx ; Data Port (0x03C5) + + mov bl, 1 ; Mask initial : Plan 0 (0001b) + .plan_loop: + mov al, bl + out dx, al ; Activer l'écriture uniquement sur ce plan + + push di + mov cx, 16 + .row_loop: + lodsw ; Lit 2 octets + mov [es:di], ax + lodsb ; Lit le 3eme octet + mov [es:di+2], al + add di, 80 + loop .row_loop + + pop di + shl bl, 1 ; Plan suivant (1 -> 2 -> 4 -> 8) + cmp bl, 16 ; Fini après le plan 3 (8) + jne .plan_loop + + ; Rétablir le Map Mask sur tous les plans (0x0F) + mov dx, VGA_SEQUENCER + mov ax, 0x0F02 + out dx, ax + + pop es + mov byte [BDA_MOUSE + mouse.bkg_saved], 0 + .done: + ret + +; ============================================================ +; vga_cursor_draw +; Détruit: registres sauvegardés/restaurés (PUSHA/POPA) +; ============================================================ +vga_cursor_draw: + push bp + mov bp, sp + sub sp, 4 ; [bp-2]: height, [bp-4]: x_bit_offset + ; local variables + %define .height word [bp-2] + %define .bit_ofs word [bp-4] + + pushad + push ds + push es + push gs + ; Note: pushad sauvegarde déjà tous les registres généraux (EAX...EDI) + + cld ; Sécurité : Direction avant + mov ax, BDA_CUSTOM_SEG + mov ds, ax + mov ax, VIDEO_SEG + mov es, ax + + ; --- CLIPPING VERTICAL --- + mov dx, [BDA_MOUSE + mouse.y] + mov bx, GFX_HEIGHT + cmp dx, bx + jae .exit_total + + mov ax, 16 + sub bx, dx + cmp ax, bx + jbe .y_ok + + mov ax, bx + .y_ok: + mov .height, ax + + ; --- Calcul Adresse et Shift --- + mov ax, [BDA_MOUSE + mouse.x] + mov cx, ax + and ax, 7 ; Reste (0-7) = décalage de bit + mov .bit_ofs, ax + call vga_calc_addr ; DI = VRAM Offset + + ; --- CONFIG VGA (Write Mode 0, Logic Ops) --- + mov dx, VGA_SEQUENCER + mov ax, 0x0F02 ; Map Mask = All planes + out dx, ax + + mov dx, 0x3CE ; Graphics Controller + mov ax, 0x0005 ; Mode 0 + out dx, ax + mov ax, 0x0001 ; Enable Set/Reset = 0 (CPU Data) + out dx, ax + mov ax, 0xFF08 ; Bit Mask = 0xFF + out dx, ax + + ; Source du Sprite -> (GS:SI) + mov ax, [BDA_MOUSE + mouse.cur_seg] + mov gs, ax + mov si, [BDA_MOUSE + mouse.cur_ofs] + + .row_loop: + ; --- PREPARE MASKS --- + ; On récupère le masque de l'image (AND) et du curseur (XOR) + mov ax, [gs:si] ; AX = AND Mask (16 bits) + xchg al, ah ; Souvent nécessaire selon l'endianness du sprite + xor ebx, ebx + mov bx, ax + not ebx ; On veut des 1 partout sauf là où le curseur est présent + + ; Décalage pour l'alignement au pixel près + mov cx, .bit_ofs + ror ebx, cl ; Rotation pour ne pas perdre de bits + + ; --- CONFIG VGA POUR AND --- + mov dx, 0x3CE + mov ax, 0x0803 ; Data Rotate/Function Select: AND (bits 3-4 = 01b) + out dx, ax + + ; Application sur 3 octets (pour couvrir les 16 pixels + le shift) + %rep 3 + mov al, [es:di] ; CHARGE LES LATCHES (Indispensable) + mov eax, ebx + shr eax, 16 ; Récupère la partie haute (si 32-bit shift utilisé) + stosb ; Écrit AL et DI++ (Applique le AND sur les 4 plans) + %endrep + sub di, 3 ; Revient au début de la ligne pour le XOR + + ; --- CONFIG VGA POUR XOR --- + mov ax, 0x1803 ; Data Rotate/Function Select: XOR (bits 3-4 = 11b) + out dx, ax + + ; Récupération du masque XOR (la forme blanche/noire du curseur) + mov ax, [gs:si+32] + ; ... (Appliquer le même décalage et stosb que pour le AND) ... + + ; --- NEXT ROW --- + add di, 80 - 3 ; Ligne suivante (80 octets par ligne) + add si, 2 + dec word .height + jnz .row_loop + + ; --- RESTORE VGA --- + mov dx, 0x3CE + mov ax, 0x0003 ; Function = Replace + out dx, ax + mov ax, 0xFF08 ; Bit Mask = 0xFF + out dx, ax + mov ax, 0x0001 ; Enable Set/Reset = 0 + out dx, ax + + .exit_total: + pop gs + pop es + pop ds + popad + leave + ret +%undef .height +%undef .mask diff --git a/src/drivers/mouse_ps2.asm b/src/drivers/mouse_ps2.asm index b106abb..fad7943 100644 --- a/src/drivers/mouse_ps2.asm +++ b/src/drivers/mouse_ps2.asm @@ -43,7 +43,7 @@ ; ; ------------------------------------------------------------ mouse_reset: - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov fs,ax ; effacer les variables du drivers @@ -52,8 +52,8 @@ mouse_reset: mov byte [fs:BDA_MOUSE + mouse.packetlen],3 ; 3 bytes par défaut mov byte [fs:BDA_MOUSE + mouse.status],0 - mov word [fs:BDA_MOUSE + mouse.x],320 ; vous pouvez aussi préciser le centre - mov word [fs:BDA_MOUSE + mouse.y],100 ; vous pouvez aussi préciser le centre + mov word [fs:BDA_MOUSE + mouse.x],GFX_WIDTH / 2 + mov word [fs:BDA_MOUSE + mouse.y],GFX_HEIGHT / 2 mov word [fs:BDA_MOUSE + mouse.cur_x], 0 mov word [fs:BDA_MOUSE + mouse.cur_y], 0 @@ -154,7 +154,7 @@ mouse_init: ; ; ------------------------------------------------------------ mouse_detect_packet_len: - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov fs,ax mov byte [fs:BDA_MOUSE + mouse.packetlen], 3 @@ -284,7 +284,7 @@ isr_mouse_handler: push ds ; use BDA segment - mov ax,BDA_DATA_SEG + mov ax,BDA_CUSTOM_SEG mov ds,ax ; lire un octet depuis le contrôleur et le stocker dans le buffer diff --git a/src/gui/lib-api.asm b/src/gui/lib-api.asm new file mode 100644 index 0000000..83ff51c --- /dev/null +++ b/src/gui/lib-api.asm @@ -0,0 +1,528 @@ +; ============================================================================= +; Project : Custom BIOS / ROM +; File : gui/lib.asm +; Author : frater +; +; License : GNU General Public License v3.0 or later (GPL-3.0+) +; +; This program is free software: you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 3 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program. If not, see . +; +; ============================================================================= + +; --- Configuration --- +%define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés + +; Dimensions +%define GUI_CHECKBOX_SIZE 10 ; + +; --- Drapeaux & États --- +%define GUI_STATE_FREE 0 ; Le slot est vide (mémoire dispo) +%define GUI_STATE_NORMAL 1 ; Affiché, repos +%define GUI_STATE_HOVER 2 ; Souris dessus +%define GUI_STATE_PRESSED 3 ; Clic enfoncé +%define GUI_STATE_DISABLED 4 ; Grisé + +; --- Types de Widgets --- +%define OBJ_TYPE_LABEL 0 +%define OBJ_TYPE_BUTTON 1 +%define OBJ_TYPE_SLIDER 2 +%define OBJ_TYPE_BUTTON_ROUNDED 3 +%define OBJ_TYPE_CHECKBOX 4 + +; --- Widgets attributs --- +%define BUTTON_DEFAULT 0 +%define BUTTON_OK 1 + +%define SLIDER_HORIZONTAL 1 +%define SLIDER_VERTICAL 2 + +; ============================================================================= +; SECTION : API ACTIONS +; ============================================================================= + +%define OBJ_CREATE 0 +%define OBJ_DESTROY 1 +%define OBJ_GET_STATE 2 +%define OBJ_GET_TYPE 3 +%define OBJ_GET_VAL 4 +%define OBJ_SET_VAL 5 + +%define OBJ_SET_MODE 6 +%define OBJ_SET_TEXT 7 + +%define OBJ_GET_PTR 8 + +%define OBJ_SLIDER_SET_ATTR 9 + + +gui_api_table: + dw gui_api_create + dw gui_api_destroy + dw gui_api_get_state + dw gui_api_get_type + dw gui_api_get_val + dw gui_api_set_val + dw gui_api_set_mode + dw gui_api_set_text + dw gui_get_widget_ptr + dw gui_api_slider_attr + + +; --- Structure d'un OBJET (Bouton, etc) --- +struc widget + .state resb 1 ; État (0=libre, >0=utilisé) + .type resb 1 ; Type (0=Button, 1=Slider...) + .oldstate resb 1 ; widget a-t-il été modifié ? + .user_id resb 1 ; ID unique utilisateur + .x resw 1 ; Position X + .y resw 1 ; Position Y + .x2 resw 1 ; Position X2 calculée + .y2 resw 1 ; Position Y2 calculée + .w resw 1 ; Largeur + .h resw 1 ; Hauteur + .text_ofs resw 1 ; Offset du texte + .text_seg resw 1 ; Segment du texte + .event_click resw 1 ; adresse de la fonction "on click" + .event_drag resw 1 ; adresse de la fonction "on drag" + + .attr_mode resb 1 ; 0=None, 1=Horiz, 2=Vert + .attr_min resw 1 ; Valeur/Position Min + .attr_max resw 1 ; Valeur/Position Max + .attr_val resw 1 ; Valeur/Position Actuelle + + .thumb_pos resw 1 ; Valeur/Position Actuelle en pixel pour le dessin. + .thumb_pct resb 1 ; Taille du curseur en % (1-100) + + .attr_anchor resw 1 ; interne Offset pour le drag + alignb 2 ; Alignement mémoire pour performance +endstruc +; actuellement 34 octets + +%macro GUI 1-* + %rep %0 - 1 + %rotate -1 + push %1 + %endrep + %rotate -1 + call word [cs:gui_api_table + ((%1)*2)] + add sp, (%0 - 1) * 2 +%endmacro + +; ----------------------------------------------------------------------------- +; gui_api_slider_attr +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +%define .min word [bp+6] +%define .max word [bp+8] +%define .val word [bp+10] +%define .pct word [bp+12] +gui_api_slider_attr: + push bp + mov bp, sp + push ax + + push .id ; ID + call gui_get_widget_ptr + jc .err + + mov ax, .min + mov word [gs:si + widget.attr_min], ax + mov ax, .max + mov word [gs:si + widget.attr_max], ax + mov ax, .val + mov word [gs:si + widget.attr_val], ax + mov ax, .pct + mov byte [gs:si + widget.thumb_pct], al + + call gui_slider_update_pixels + + .err: + pop ax + leave + ret +%undef .id +%undef .mode + +; ----------------------------------------------------------------------------- +; gui_api_set_mode +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +%define .mode word [bp+6] +gui_api_set_mode: + push bp + mov bp, sp + push ax + + push .id + call gui_get_widget_ptr + jc .err + + mov ax, .mode + mov byte [gs:si + widget.attr_mode], al + + .err: + pop ax + leave + ret +%undef .id +%undef .mode + +; ----------------------------------------------------------------------------- +; gui_api_set_text +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +%define .segmt word [bp+6] +%define .oft word [bp+8] +gui_api_set_text: + push bp + mov bp, sp + push ax + + push .id + call gui_get_widget_ptr + jc .err + + mov ax, .segmt + mov word [gs:si + widget.text_seg], ax + mov ax, .oft ; Offset du texte + mov word [gs:si + widget.text_ofs], ax + + .err: + pop ax + leave + ret +%undef .id +%undef .text_ofs +%undef .text_seg + +; ----------------------------------------------------------------------------- +; gui_api_create +; Crée un widget et retourne son ID +; Out: AX = ID ou -1 si erreur +; +; parameters : type, x, y, w, h, text_ofs, text_seg +; +; ----------------------------------------------------------------------------- +%define .type word [bp+4] +%define .x word [bp+6] +%define .y word [bp+8] +%define .w word [bp+10] +%define .h word [bp+12] +gui_api_create: + push bp + mov bp, sp + push gs + + mov ax, BDA_GUI_WIDGET + mov gs, ax + call gui_alloc_widget ; Returns GS:SI + mov ax, -1 + jc .done + + ; ID = SI / widget_size + mov ax, si + xor dx, dx + mov cx, widget_size + div cx + + mov bx, .type + mov byte [gs:si + widget.type], bl + mov bx, .x + mov word [gs:si + widget.x], bx + mov bx, .y + mov word [gs:si + widget.y], bx + mov bx, .w + mov word [gs:si + widget.w], bx + mov bx, .h + mov word [gs:si + widget.h], bx + + mov byte [gs:si + widget.state], GUI_STATE_NORMAL + mov byte [gs:si + widget.oldstate], 0 +.done: + pop gs + leave + ret +%undef .type +%undef .x +%undef .y +%undef .w +%undef .h + +; ----------------------------------------------------------------------------- +; gui_api_get_state +; Arg1: ID +; Out: AX = State +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +gui_api_get_state: + push bp + mov bp, sp + + mov ax, .id ; ID + call gui_get_widget_ptr + jc .err + + xor ax, ax + mov al, [gs:si + widget.state] + jmp .done + +.err: + mov ax, -1 +.done: + leave + ret +%undef .id + +; ----------------------------------------------------------------------------- +; gui_api_get_type +; Arg1: ID +; Out: AX = Type +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +gui_api_get_type: + push bp + mov bp, sp + + mov ax, .id ; ID + call gui_get_widget_ptr + jc .err + + xor ax, ax + mov al, [gs:si + widget.type] + jmp .done + +.err: + mov ax, -1 +.done: + leave + ret +%undef .id + +; ----------------------------------------------------------------------------- +; gui_api_get_val +; Arg1: ID +; Out: AX = Attr Val +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +gui_api_get_val: + push bp + mov bp, sp + + call gui_get_widget_ptr + ;jc .err + + call gui_slider_update_value + mov ax, [gs:si + widget.attr_val] + jmp .done + +.err: + mov ax, -1 +.done: + leave + ret +%undef .id + +; ----------------------------------------------------------------------------- +; gui_api_set_val +; Arg1: ID +; Arg2: Value +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +%define .val word [bp+6] +gui_api_set_val: + push bp + mov bp, sp + + mov ax, .id ; ID + call gui_get_widget_ptr + jc .err + + mov ax, .val + mov [gs:si + widget.thumb_pos], ax + +.err: + leave + ret +%undef .id +%undef .val + +; ----------------------------------------------------------------------------- +; gui_api_destroy +; Détruit un widget via son ID +; Arg1: ID +; Out: AX = 0 (OK), -1 (Error) +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +gui_api_destroy: + push bp + mov bp, sp + + mov ax, .id ; ID + call gui_get_widget_ptr + jc .err + + call gui_free_widget + xor ax, ax + jmp .done + +.err: + mov ax, -1 +.done: + leave + ret +%undef .id + +; ----------------------------------------------------------------------------- +; gui_get_widget_ptr +; Helper interne : Convertit ID en Pointeur +; In: ID +; Out: GS:SI = Ptr, CF=1 if error +; ----------------------------------------------------------------------------- +%define .id word [bp+4] +gui_get_widget_ptr: + push bp + mov bp, sp + push ax + push cx + + mov ax, .id + cmp ax, GUI_MAX_WIDGETS + jae .error + + mov cx, widget_size + xor dx, dx + mul cx ; AX = Offset + mov si, ax + + mov ax, BDA_GUI_WIDGET + mov gs, ax + + clc + jmp .done + .error: + stc + .done: + pop cx + pop ax + leave + ret +%undef .id + + +; ============================================================================= +; SECTION : GESTION MÉMOIRE (ALLOCATION / LIBÉRATION) +; ============================================================================= + +; ----------------------------------------------------------------------------- +; gui_init_system +; Initialise toute la mémoire des widgets à 0 (Libre) +; Entrée : DS doit pointer vers BDA_GUI_WIDGET +; ----------------------------------------------------------------------------- +gui_init_system: + push eax + push cx + push es + push di + + mov ax, BDA_GUI_WIDGET + mov es, ax + + cld + xor di, di + mov cx, (widget_size * GUI_MAX_WIDGETS) / 2 + xor ax, ax + rep stosw ; Plus sûr en mode 16 bits pour l'alignement + + pop di + pop es + pop cx + pop eax + ret + +; ----------------------------------------------------------------------------- +; gui_alloc_widget +; Cherche un slot vide et retourne son adresse +; Sortie : +; - Succès : CF=0 (Carry Clear), GS:SI = Offset du widget +; - Echec : CF=1 (Carry Set), GS:SI = Indéfini (ou 0) +; ----------------------------------------------------------------------------- +gui_alloc_widget: + push ax + push cx + push bx + + mov ax, BDA_GUI_WIDGET + mov gs, ax + + mov si, 0 ; Début du pool + mov cx, GUI_MAX_WIDGETS + + .loop_find: + cmp byte [gs:si + widget.state], GUI_STATE_FREE + je .found ; Si state == 0, c'est libre ! + + add si, widget_size ; Sinon on passe au suivant + loop .loop_find + + ; Pas trouvé (Plein) + stc ; set Carry Flag : erreur + jmp .done + + .found: + ; On initialise le slot trouvé + mov byte [gs:si + widget.state], GUI_STATE_NORMAL ; Marquer comme occupé + mov byte [gs:si + widget.type], OBJ_TYPE_BUTTON ; Type par défaut + mov byte [gs:si + widget.oldstate], 0 ; doit etre dessiné + + ; Reset des champs critiques pour éviter les déchets + mov word [gs:si + widget.event_click], 0 + mov word [gs:si + widget.event_drag], 0 + mov byte [gs:si + widget.thumb_pct], 10 ; 10% par défaut + + clc ; Clear Carry Flag + .done: + pop bx + pop cx + pop ax + ret + +; ----------------------------------------------------------------------------- +; gui_free_widget +; Libère un widget +; Entrée : SI = Pointeur widget +; ----------------------------------------------------------------------------- +gui_free_widget: + push eax + push es + + mov ax, BDA_GUI_WIDGET + mov es, ax + + cld + mov di, si + mov cx, (widget_size) + shr cx, 2 ; cx / 4 + xor eax, eax + rep stosd ; Remplit tout de 0 + + ; On efface le widget + mov byte [es:si + widget.state], GUI_STATE_FREE + ; Pour l'instant on le marque juste libre, il n'est pas retirer de l'écran. + + pop es + pop eax + ret + +%include "./gui/lib-logic.asm" +%include "./gui/lib-draw.asm" diff --git a/src/gui/draw.asm b/src/gui/lib-draw.asm similarity index 99% rename from src/gui/draw.asm rename to src/gui/lib-draw.asm index 3db5cd9..e67a82a 100644 --- a/src/gui/draw.asm +++ b/src/gui/lib-draw.asm @@ -31,7 +31,7 @@ gui_draw_single_widget: GFX MOUSE_HIDE ; On cache la souris AVANT de commencer le dessin du widget - mov ax, GUI_RAM_SEG + mov ax, BDA_GUI_WIDGET mov gs, ax mov al, [gs:si + widget.state] @@ -291,12 +291,12 @@ draw_button: .draw_default_style: ; Bordure extérieure épaisse (2px) - GFX RECTANGLE, ax, bx, cx, dx, 0 + ;GFX RECTANGLE, ax, bx, cx, dx, 0 inc ax inc bx dec cx dec dx - GFX RECTANGLE, ax, bx, cx, dx, 0 + ;GFX RECTANGLE, ax, bx, cx, dx, 0 ; Bordure intérieure fine (après un gap de 1px blanc) add ax, 2 diff --git a/src/gui/lib.asm b/src/gui/lib-logic.asm similarity index 51% rename from src/gui/lib.asm rename to src/gui/lib-logic.asm index 1586a44..346a723 100644 --- a/src/gui/lib.asm +++ b/src/gui/lib-logic.asm @@ -1,530 +1,3 @@ -; ============================================================================= -; Project : Custom BIOS / ROM -; File : gui/lib.asm -; Author : frater -; -; License : GNU General Public License v3.0 or later (GPL-3.0+) -; -; This program is free software: you can redistribute it and/or modify -; it under the terms of the GNU General Public License as published by -; the Free Software Foundation, either version 3 of the License, or -; (at your option) any later version. -; -; This program is distributed in the hope that it will be useful, -; but WITHOUT ANY WARRANTY; without even the implied warranty of -; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -; GNU General Public License for more details. -; -; You should have received a copy of the GNU General Public License -; along with this program. If not, see . -; -; ============================================================================= - -; --- Configuration --- -%define GUI_RAM_SEG 0x080 ; Segment de données UI (Safe: après Stack, avant Heap) -%define GUI_MAX_WIDGETS 32 ; Nombre max de widgets simultanés - -; Dimensions -%define GUI_CHECKBOX_SIZE 10 ; - -; --- Drapeaux & États --- -%define GUI_STATE_FREE 0 ; Le slot est vide (mémoire dispo) -%define GUI_STATE_NORMAL 1 ; Affiché, repos -%define GUI_STATE_HOVER 2 ; Souris dessus -%define GUI_STATE_PRESSED 3 ; Clic enfoncé -%define GUI_STATE_DISABLED 4 ; Grisé - -; --- Types de Widgets --- -%define OBJ_TYPE_LABEL 0 -%define OBJ_TYPE_BUTTON 1 -%define OBJ_TYPE_SLIDER 2 -%define OBJ_TYPE_BUTTON_ROUNDED 3 -%define OBJ_TYPE_CHECKBOX 4 - -; --- Widgets attributs --- -%define BUTTON_DEFAULT 0 -%define BUTTON_OK 1 - -%define SLIDER_HORIZONTAL 1 -%define SLIDER_VERTICAL 2 - -; ============================================================================= -; SECTION : API ACTIONS -; ============================================================================= - -%define OBJ_CREATE 0 -%define OBJ_DESTROY 1 -%define OBJ_GET_STATE 2 -%define OBJ_GET_TYPE 3 -%define OBJ_GET_VAL 4 -%define OBJ_SET_VAL 5 - -%define OBJ_SET_MODE 6 -%define OBJ_SET_TEXT 7 - -%define OBJ_GET_PTR 8 - -%define OBJ_SLIDER_SET_ATTR 9 - - -gui_api_table: - dw gui_api_create - dw gui_api_destroy - dw gui_api_get_state - dw gui_api_get_type - dw gui_api_get_val - dw gui_api_set_val - dw gui_api_set_mode - dw gui_api_set_text - dw gui_get_widget_ptr - dw gui_api_slider_attr - - -; --- Structure d'un OBJET (Bouton, etc) --- -struc widget - .state resb 1 ; État (0=libre, >0=utilisé) - .type resb 1 ; Type (0=Button, 1=Slider...) - .oldstate resb 1 ; widget a-t-il été modifié ? - .user_id resb 1 ; ID unique utilisateur - .x resw 1 ; Position X - .y resw 1 ; Position Y - .x2 resw 1 ; Position X2 calculée - .y2 resw 1 ; Position Y2 calculée - .w resw 1 ; Largeur - .h resw 1 ; Hauteur - .text_ofs resw 1 ; Offset du texte - .text_seg resw 1 ; Segment du texte - .event_click resw 1 ; adresse de la fonction "on click" - .event_drag resw 1 ; adresse de la fonction "on drag" - - .attr_mode resb 1 ; 0=None, 1=Horiz, 2=Vert - .attr_min resw 1 ; Valeur/Position Min - .attr_max resw 1 ; Valeur/Position Max - .attr_val resw 1 ; Valeur/Position Actuelle - - .thumb_pos resw 1 ; Valeur/Position Actuelle en pixel pour le dessin. - .thumb_pct resb 1 ; Taille du curseur en % (1-100) - - .attr_anchor resw 1 ; interne Offset pour le drag - alignb 2 ; Alignement mémoire pour performance -endstruc -; actuellement 34 octets - -%macro GUI 1-* - %rep %0 - 1 - %rotate -1 - push %1 - %endrep - %rotate -1 - call word [cs:gui_api_table + ((%1)*2)] - add sp, (%0 - 1) * 2 -%endmacro - -; ----------------------------------------------------------------------------- -; gui_api_slider_attr -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -%define .min word [bp+6] -%define .max word [bp+8] -%define .val word [bp+10] -%define .pct word [bp+12] -gui_api_slider_attr: - push bp - mov bp, sp - push ax - - push .id ; ID - call gui_get_widget_ptr - jc .err - - mov ax, .min - mov word [gs:si + widget.attr_min], ax - mov ax, .max - mov word [gs:si + widget.attr_max], ax - mov ax, .val - mov word [gs:si + widget.attr_val], ax - mov ax, .pct - mov byte [gs:si + widget.thumb_pct], al - - call gui_slider_update_pixels - - .err: - pop ax - leave - ret -%undef .id -%undef .mode - -; ----------------------------------------------------------------------------- -; gui_api_set_mode -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -%define .mode word [bp+6] -gui_api_set_mode: - push bp - mov bp, sp - push ax - - push .id - call gui_get_widget_ptr - jc .err - - mov ax, .mode - mov byte [gs:si + widget.attr_mode], al - - .err: - pop ax - leave - ret -%undef .id -%undef .mode - -; ----------------------------------------------------------------------------- -; gui_api_set_text -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -%define .segmt word [bp+6] -%define .oft word [bp+8] -gui_api_set_text: - push bp - mov bp, sp - push ax - - push .id - call gui_get_widget_ptr - jc .err - - mov ax, .segmt - mov word [gs:si + widget.text_seg], ax - mov ax, .oft ; Offset du texte - mov word [gs:si + widget.text_ofs], ax - - .err: - pop ax - leave - ret -%undef .id -%undef .text_ofs -%undef .text_seg - -; ----------------------------------------------------------------------------- -; gui_api_create -; Crée un widget et retourne son ID -; Out: AX = ID ou -1 si erreur -; -; parameters : type, x, y, w, h, text_ofs, text_seg -; -; ----------------------------------------------------------------------------- -%define .type word [bp+4] -%define .x word [bp+6] -%define .y word [bp+8] -%define .w word [bp+10] -%define .h word [bp+12] -gui_api_create: - push bp - mov bp, sp - push gs - - mov ax, GUI_RAM_SEG - mov gs, ax - call gui_alloc_widget ; Returns GS:SI - mov ax, -1 - jc .done - - ; ID = SI / widget_size - mov ax, si - xor dx, dx - mov cx, widget_size - div cx - - mov bx, .type - mov byte [gs:si + widget.type], bl - mov bx, .x - mov word [gs:si + widget.x], bx - mov bx, .y - mov word [gs:si + widget.y], bx - mov bx, .w - mov word [gs:si + widget.w], bx - mov bx, .h - mov word [gs:si + widget.h], bx - - mov byte [gs:si + widget.state], GUI_STATE_NORMAL - mov byte [gs:si + widget.oldstate], 0 -.done: - pop gs - leave - ret -%undef .type -%undef .x -%undef .y -%undef .w -%undef .h - -; ----------------------------------------------------------------------------- -; gui_api_get_state -; Arg1: ID -; Out: AX = State -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -gui_api_get_state: - push bp - mov bp, sp - - mov ax, .id ; ID - call gui_get_widget_ptr - jc .err - - xor ax, ax - mov al, [gs:si + widget.state] - jmp .done - -.err: - mov ax, -1 -.done: - leave - ret -%undef .id - -; ----------------------------------------------------------------------------- -; gui_api_get_type -; Arg1: ID -; Out: AX = Type -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -gui_api_get_type: - push bp - mov bp, sp - - mov ax, .id ; ID - call gui_get_widget_ptr - jc .err - - xor ax, ax - mov al, [gs:si + widget.type] - jmp .done - -.err: - mov ax, -1 -.done: - leave - ret -%undef .id - -; ----------------------------------------------------------------------------- -; gui_api_get_val -; Arg1: ID -; Out: AX = Attr Val -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -gui_api_get_val: - push bp - mov bp, sp - - call gui_get_widget_ptr - ;jc .err - - call gui_slider_update_value - mov ax, [gs:si + widget.attr_val] - jmp .done - -.err: - mov ax, -1 -.done: - leave - ret -%undef .id - -; ----------------------------------------------------------------------------- -; gui_api_set_val -; Arg1: ID -; Arg2: Value -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -%define .val word [bp+6] -gui_api_set_val: - push bp - mov bp, sp - - mov ax, .id ; ID - call gui_get_widget_ptr - jc .err - - mov ax, .val - mov [gs:si + widget.thumb_pos], ax - -.err: - leave - ret -%undef .id -%undef .val - -; ----------------------------------------------------------------------------- -; gui_api_destroy -; Détruit un widget via son ID -; Arg1: ID -; Out: AX = 0 (OK), -1 (Error) -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -gui_api_destroy: - push bp - mov bp, sp - - mov ax, .id ; ID - call gui_get_widget_ptr - jc .err - - call gui_free_widget - xor ax, ax - jmp .done - -.err: - mov ax, -1 -.done: - leave - ret -%undef .id - -; ----------------------------------------------------------------------------- -; gui_get_widget_ptr -; Helper interne : Convertit ID en Pointeur -; In: ID -; Out: GS:SI = Ptr, CF=1 if error -; ----------------------------------------------------------------------------- -%define .id word [bp+4] -gui_get_widget_ptr: - push bp - mov bp, sp - push ax - push cx - - mov ax, .id - cmp ax, GUI_MAX_WIDGETS - jae .error - - mov cx, widget_size - xor dx, dx - mul cx ; AX = Offset - mov si, ax - - mov ax, GUI_RAM_SEG - mov gs, ax - - clc - jmp .done - .error: - stc - .done: - pop cx - pop ax - leave - ret -%undef .id - - -; ============================================================================= -; SECTION : GESTION MÉMOIRE (ALLOCATION / LIBÉRATION) -; ============================================================================= - -; ----------------------------------------------------------------------------- -; gui_init_system -; Initialise toute la mémoire des widgets à 0 (Libre) -; Entrée : DS doit pointer vers GUI_RAM_SEG -; ----------------------------------------------------------------------------- -gui_init_system: - push eax - push cx - push es - push di - - mov ax, GUI_RAM_SEG - mov es, ax - - cld - xor di, di - mov cx, (widget_size * GUI_MAX_WIDGETS) / 2 - xor ax, ax - rep stosw ; Plus sûr en mode 16 bits pour l'alignement - - pop di - pop es - pop cx - pop eax - ret - -; ----------------------------------------------------------------------------- -; gui_alloc_widget -; Cherche un slot vide et retourne son adresse -; Sortie : -; - Succès : CF=0 (Carry Clear), GS:SI = Offset du widget -; - Echec : CF=1 (Carry Set), GS:SI = Indéfini (ou 0) -; ----------------------------------------------------------------------------- -gui_alloc_widget: - push ax - push cx - push bx - - mov ax, GUI_RAM_SEG - mov gs, ax - - mov si, 0 ; Début du pool - mov cx, GUI_MAX_WIDGETS - - .loop_find: - cmp byte [gs:si + widget.state], GUI_STATE_FREE - je .found ; Si state == 0, c'est libre ! - - add si, widget_size ; Sinon on passe au suivant - loop .loop_find - - ; Pas trouvé (Plein) - stc ; set Carry Flag : erreur - jmp .done - - .found: - ; On initialise le slot trouvé - mov byte [gs:si + widget.state], GUI_STATE_NORMAL ; Marquer comme occupé - mov byte [gs:si + widget.type], OBJ_TYPE_BUTTON ; Type par défaut - mov byte [gs:si + widget.oldstate], 0 ; doit etre dessiné - - ; Reset des champs critiques pour éviter les déchets - mov word [gs:si + widget.event_click], 0 - mov word [gs:si + widget.event_drag], 0 - mov byte [gs:si + widget.thumb_pct], 10 ; 10% par défaut - - clc ; Clear Carry Flag - .done: - pop bx - pop cx - pop ax - ret - -; ----------------------------------------------------------------------------- -; gui_free_widget -; Libère un widget -; Entrée : SI = Pointeur widget -; ----------------------------------------------------------------------------- -gui_free_widget: - push eax - push es - - mov ax, GUI_RAM_SEG - mov es, ax - - cld - mov di, si - mov cx, (widget_size) - shr cx, 2 ; cx / 4 - xor eax, eax - rep stosd ; Remplit tout de 0 - - ; On efface le widget - mov byte [es:si + widget.state], GUI_STATE_FREE - ; Pour l'instant on le marque juste libre, il n'est pas retirer de l'écran. - - pop es - pop eax - ret - ; ============================================================================= ; SECTION : MOTEUR D'ÉVÉNEMENTS (EVENT LOOP) ; ============================================================================= @@ -543,12 +16,12 @@ gui_process_all: push ds push gs - mov ax, GUI_RAM_SEG + mov ax, BDA_GUI_WIDGET mov gs, ax ; Charger l'état de la souris pour toute la passe push ds - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax mov bl, [BDA_MOUSE + mouse.status] pop ds @@ -612,9 +85,9 @@ gui_update_logic: push ds push gs - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax - mov ax, GUI_RAM_SEG + mov ax, BDA_GUI_WIDGET mov gs, ax mov al, byte [gs:si + widget.state] @@ -962,7 +435,7 @@ gui_logic_slider: ; 4. Target Pos = MouseX - Anchor ; On recharge MouseX depuis la BDA pour être sûr push ds - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax mov ax, [BDA_MOUSE + mouse.x] pop ds @@ -990,7 +463,7 @@ gui_logic_slider: ; 4. Target Pos = MouseY - Anchor ; On recharge MouseY depuis la BDA pour être sûr push ds - mov ax, BDA_DATA_SEG + mov ax, BDA_CUSTOM_SEG mov ds, ax mov ax, [BDA_MOUSE + mouse.y] pop ds