org 0x0
bits 16

%define ENDL 0x0D, 0x0A

; Constants for SoftGPU
SCREEN_WIDTH  equ 320
SCREEN_HEIGHT equ 200
VGA_SEGMENT   equ 0xA000

start:
    ; Initialize stack
    xor ax, ax
    mov ss, ax
    mov sp, 0x7C00

    call clear_screen

    ; Print welcome message
    mov si, msg_welcome
    call puts

; Add this after the gets call in your command_loop
; to ensure proper newline after input

command_loop:
    mov si, msg_prompt
    call puts

    mov di, input_buffer
    call gets
   
    ; ADD THIS: Print newline after getting input
    mov si, msg_newline
    call puts

    call parse_command

    jmp command_loop
; -------------------------------------
; Clear screen via setting text mode
clear_screen:
    push ax
    push bx
    mov ah, 0x00
    mov al, 0x03
    int 0x10
    mov ah, 0x02
    mov bh, 0
    mov dh, 0
    mov dl, 0
    int 0x10
    pop bx
    pop ax
    ret
; -------------------------------------
; Read a line from keyboard into [DI] (buffer)
; - DI: pointer to buffer (caller sets)
; - Buffer will be NUL-terminated
; - Max length = 79 characters (keeps room for NUL)
; - Echoes characters, supports Backspace (ASCII 8)
; - Stops on Enter (CR, 0x0D)
gets:
    push ax
    push bx
    push cx
    push dx
    push si
    push di
    push bp

    mov si, di        ; SI = base pointer to buffer
    xor cx, cx        ; CX = count

.get_char:
    ; Wait for keystroke (BIOS)
    mov ah, 0x00
    int 0x16          ; AL = ASCII, AH = scancode

    cmp al, 0x0D      ; Enter? (CR)
    je .done

    cmp al, 0x08      ; Backspace?
    je .backspace

    ; Ignore NUL
    cmp al, 0x00
    je .get_char

    ; If printable, store and echo
    ; Check length limit (79 chars)
    cmp cx, 79
    jae .beep_and_wait

    ; Store char - use BP as temporary index register
    mov bp, si
    add bp, cx
    mov [bp], al
    inc cx

    ; Echo char using teletype (int10 AH=0x0E)
    push dx           ; preserve DX
    mov ah, 0x0E
    mov bh, 0x00      ; page 0
    mov bl, 0x00
    int 0x10
    pop dx

    jmp .get_char

.backspace:
    cmp cx, 0
    je .get_char      ; nothing to delete -> continue waiting

    dec cx
    ; Erase char on screen: Backspace, space, Backspace
    push dx
    mov ah, 0x0E
    mov bh, 0x00
    mov al, 0x08      ; BS
    int 0x10
    mov ah, 0x0E
    mov al, ' '
    int 0x10
    mov ah, 0x0E
    mov al, 0x08
    int 0x10
    pop dx
    jmp .get_char

.beep_and_wait:
    ; optional feedback when buffer full: flash beep
    mov ah, 0x0E
    mov al, 0x07
    int 0x10
    jmp .get_char

.done:
    ; Null-terminate buffer - use BP as temporary
    mov bp, si
    add bp, cx
    mov byte [bp], 0

    pop bp
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret
; -------------------------------------
; Parse and execute command
parse_command:
    push si
    push di
    push bx

    mov si, input_buffer

.skip_spaces:
    mov al, [si]
    cmp al, ' '
    jne .not_space
    inc si
    jmp .skip_spaces
.not_space:

    cmp byte [si], 0
    je .done

        mov di, cmd_help
    call strcmp
    cmp ax, 0
    je cmd_help_handler

    mov di, cmd_clear
    call strcmp
    cmp ax, 0
    je cmd_clear_handler

    mov di, cmd_echo
    call strcmp
    cmp ax, 0
    je cmd_echo_handler

    mov di, cmd_reboot
    call strcmp
    cmp ax, 0
    je cmd_reboot_handler

    mov di, cmd_beep
    call strcmp
    cmp ax, 0
    je cmd_beep_handler

    mov di, cmd_test
    call strcmp
    cmp ax, 0
    je cmd_test_handler

    mov di, cmd_color
    call strcmp
    cmp ax, 0
    je cmd_color_handler

    mov di, cmd_pixel
    call strcmp
    cmp ax, 0
    je cmd_pixel_handler

    mov di, cmd_softgpu
    call strcmp
    cmp ax, 0
    je cmd_softgpu_handler


.done:
    pop bx
    pop di
    pop si
    ret

; -------------------------------------
; String compare
strcmp:
    push ax
    push bx
    push si
    push di

.compare_loop:
    mov al, [si]
    mov ah, [di]
    cmp al, ah
    jne .not_equal
    test al, al
    jz .equal
    cmp al, ' '
    je .equal
    inc si
    inc di
    jmp .compare_loop

.equal:
    xor ax, ax       ; AX = 0 (equal)
    test ax, ax      ; set ZF = 1
    jmp .done

.not_equal:
    mov ax, 1        ; AX = 1 (not equal)
    test ax, ax      ; set ZF = 0

.done:
    pop di
    pop si
    pop bx
    pop ax
    ret




; -------------------------------------
; Command handlers

cmd_help_handler:
    mov si, msg_help_text
    call puts
    ret

cmd_clear_handler:
    call clear_screen
    mov si, msg_welcome
    call puts
    ret

cmd_echo_handler:
    mov si, input_buffer

.skip_token:
    mov al, [si]
    cmp al, ' '
    je .found_space
    cmp al, 0
    je .no_text
    inc si
    jmp .skip_token

.found_space:
    inc si
.skip_spaces2:
    mov al, [si]
    cmp al, ' '
    jne .start_text
    cmp al, 0
    je .no_text
    inc si
    jmp .skip_spaces2

.start_text:
    call puts
    mov si, msg_newline
    call puts
    ret

.no_text:
    mov si, msg_newline
    call puts
    ret

cmd_reboot_handler:
    mov si, msg_rebooting
    call puts
    mov cx, 0xFFFF
.wait:
    loop .wait
    jmp 0xFFFF:0x0000

cmd_beep_handler:
    mov ah, 0x0E
    mov al, 0x07
    int 0x10
    ret

cmd_test_handler:
    mov si, msg_test
    call puts

    mov ah, 0x00
    mov al, 0x13
    int 0x10

    push es
    mov ax, 0xA000
    mov es, ax

    mov ax, 100
    mov bx, 320
    mul bx
    add ax, 160
    mov di, ax
    mov byte [es:di], 15
    mov byte [es:di+1], 12
    mov byte [es:di+320], 12
    mov byte [es:di+321], 12

    pop es

    mov ah, 0x00
    int 0x16

    mov ah, 0x00
    mov al, 0x03
    int 0x10

    mov si, msg_welcome
    call puts
    ret

cmd_color_handler:
    mov si, msg_color_demo
    call puts

    mov ah, 0x02
    mov bh, 0
    mov dh, 10
    mov dl, 10
    int 0x10

    mov si, msg_colored
    mov bl, 0x4F
    call puts_with_color

    mov ah, 0x02
    mov bh, 0
    mov dh, 12
    mov dl, 15
    int 0x10

    mov si, msg_colored2
    mov bl, 0x2E
    call puts_with_color

    ret

cmd_pixel_handler:
    mov si, msg_pixel_demo
    call puts

    mov ah, 0x00
    mov al, 0x13
    int 0x10

    push es
    mov ax, 0xA000
    mov es, ax

    mov cx, 50
    xor dx, dx

.square_loop:
    mov ax, 75
    mov bx, 320
    mul bx
    add ax, 135
    add ax, dx
    mov di, ax
    mov byte [es:di], 14

    mov ax, 75
    add ax, 49
    mov bx, 320
    mul bx
    add ax, 135
    add ax, dx
    mov di, ax
    mov byte [es:di], 14

    mov ax, 75
    add ax, dx
    mov bx, 320
    mul bx
    add ax, 135
    mov di, ax
    mov byte [es:di], 14

    add ax, 49
    mov di, ax
    mov byte [es:di], 14

    inc dx
    loop .square_loop

    pop es

    mov ah, 0x00
    int 0x16

    mov ah, 0x00
    mov al, 0x03
    int 0x10

    mov si, msg_welcome
    call puts
    ret

; -------------------------------------
; SoftGPU Command Handler
cmd_softgpu_handler:
    mov si, msg_softgpu
    call puts

    call gpu_init
    call softgpu_draw_demo

    mov ah, 0x00
    int 0x16

    call gpu_exit

    mov si, msg_welcome
    call puts
    ret

; -------------------------------------
; SoftGPU Demo
softgpu_draw_demo:
    push ax
    push bx
    push cx
    push dx
    push si
    push di

    ; Clear to dark blue
    mov al, 1
    call gpu_clear_fast

    ; Yellow filled rectangle
    mov cx, 50
    mov dx, 50
    mov si, 100
    mov di, 60
    mov al, 14
    call gpu_fill_rect

    ; White rectangle outline
    mov cx, 180
    mov dx, 30
    mov si, 80
    mov di, 50
    mov al, 15
    call gpu_draw_rect

    ; Red diagonal line
    mov cx, 10
    mov dx, 10
    mov si, 200
    mov di, 150
    mov al, 12
    call gpu_draw_line

    ; Green horizontal line
    mov cx, 30
    mov dx, 180
    mov si, 100
    mov al, 10
    call gpu_draw_hline

    ; Cyan vertical line
    mov cx, 300
    mov dx, 20
    mov si, 150
    mov al, 11
    call gpu_draw_vline

    ; White pixel cross
    mov cx, 160
    mov dx, 100
    mov al, 15
    call gpu_set_pixel
   
    mov cx, 159
    call gpu_set_pixel
   
    mov cx, 161
    call gpu_set_pixel
   
    mov cx, 160
    mov dx, 99
    call gpu_set_pixel
   
    mov dx, 101
    call gpu_set_pixel

    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret

; ============================================================================
; SOFTGPU LIBRARY - CORRECTED VERSION
; ============================================================================

gpu_init:
    push ax
    mov ax, 0x0013
    int 0x10
    pop ax
    ret

gpu_exit:
    push ax
    mov ax, 0x0003
    int 0x10
    pop ax
    ret

gpu_set_pixel:
    push ax
    push bx
    push di
    push es
    push dx
    push cx
   
    ; Bounds check
    cmp cx, SCREEN_WIDTH
    jae .done
    cmp dx, SCREEN_HEIGHT
    jae .done
   
    ; Calculate offset
    mov ax, dx
    mov bx, SCREEN_WIDTH
    mul bx
    add ax, cx
    mov di, ax
   
    ; Write pixel
    mov bx, VGA_SEGMENT
    mov es, bx
   
    ; Get color from stack (original AL value)
    mov bx, sp
    mov al, [ss:bx+12]
    mov [es:di], al
   
.done:
    pop cx
    pop dx
    pop es
    pop di
    pop bx
    pop ax
    ret

gpu_clear_fast:
    push ax
    push cx
    push di
    push es
   
    mov bx, VGA_SEGMENT
    mov es, bx
    xor di, di
    mov cx, SCREEN_WIDTH * SCREEN_HEIGHT
    rep stosb
   
    pop es
    pop di
    pop cx
    pop ax
    ret

gpu_draw_hline:
    push ax
    push bx
    push cx
    push dx
    push di
    push es
    push si
   
    ; Bounds check
    cmp dx, SCREEN_HEIGHT
    jae .done
    cmp cx, SCREEN_WIDTH
    jae .done
   
    ; Clip length
    mov ax, cx
    add ax, si
    cmp ax, SCREEN_WIDTH
    jbe .len_ok
    mov ax, SCREEN_WIDTH
    sub ax, cx
    mov si, ax
.len_ok:
    test si, si
    jz .done
   
    ; Calculate offset
    mov ax, dx
    mov bx, SCREEN_WIDTH
    mul bx
    add ax, cx
    mov di, ax
   
    ; Setup ES
    mov bx, VGA_SEGMENT
    mov es, bx
   
    ; Get color
    mov bx, sp
    mov al, [ss:bx+14]
   
    ; Draw
    mov cx, si
.loop:
    mov [es:di], al
    inc di
    loop .loop
   
.done:
    pop si
    pop es
    pop di
    pop dx
    pop cx
    pop bx
    pop ax
    ret

gpu_draw_vline:
    push ax
    push bx
    push cx
    push dx
    push di
    push es
    push si
   
    ; Bounds check
    cmp cx, SCREEN_WIDTH
    jae .done
    cmp dx, SCREEN_HEIGHT
    jae .done
   
    ; Clip length
    mov ax, dx
    add ax, si
    cmp ax, SCREEN_HEIGHT
    jbe .len_ok
    mov ax, SCREEN_HEIGHT
    sub ax, dx
    mov si, ax
.len_ok:
    test si, si
    jz .done
   
    ; Calculate offset
    mov ax, dx
    mov bx, SCREEN_WIDTH
    mul bx
    add ax, cx
    mov di, ax
   
    ; Setup ES
    mov bx, VGA_SEGMENT
    mov es, bx
   
    ; Get color
    mov bx, sp
    mov al, [ss:bx+14]
   
    ; Draw
.loop:
    mov [es:di], al
    add di, SCREEN_WIDTH
    dec si
    jnz .loop
   
.done:
    pop si
    pop es
    pop di
    pop dx
    pop cx
    pop bx
    pop ax
    ret

gpu_fill_rect:
    push ax
    push bx
    push cx
    push dx
    push si
    push di
    push bp
   
    ; Bounds check
    cmp cx, SCREEN_WIDTH
    jae .done
    cmp dx, SCREEN_HEIGHT
    jae .done
   
    ; Clip width
    mov ax, cx
    add ax, si
    cmp ax, SCREEN_WIDTH
    jbe .width_ok
    mov ax, SCREEN_WIDTH
    sub ax, cx
    mov si, ax
.width_ok:
    test si, si
    jz .done
   
    ; Clip height
    mov ax, dx
    add ax, di
    cmp ax, SCREEN_HEIGHT
    jbe .height_ok
    mov ax, SCREEN_HEIGHT
    sub ax, dx
    mov di, ax
.height_ok:
    test di, di
    jz .done
   
    ; Get color from stack
    mov bx, sp
    mov al, [ss:bx+14]
   
    ; Save height counter
    mov bp, di
   
.row_loop:
    ; Save registers for each row
    push cx
    push dx
    push si
    push ax
   
    ; Call hline
    call gpu_draw_hline
   
    ; Restore and advance
    pop ax
    pop si
    pop dx
    pop cx
   
    inc dx
    dec bp
    jnz .row_loop
   
.done:
    pop bp
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret

gpu_draw_rect:
    push ax
    push bx
    push cx
    push dx
    push si
    push di
    push bp
   
    ; Save all parameters on stack
    mov bp, sp
    mov word [bp-2], cx    ; x
    mov word [bp-4], dx    ; y
    mov word [bp-6], si    ; width
    mov word [bp-8], di    ; height
    mov byte [bp-9], al    ; color
   
    ; Draw top line
    mov cx, [bp-2]
    mov dx, [bp-4]
    mov si, [bp-6]
    mov al, [bp-9]
    call gpu_draw_hline
   
    ; Draw bottom line
    mov cx, [bp-2]
    mov dx, [bp-4]
    add dx, [bp-8]
    dec dx
    mov si, [bp-6]
    mov al, [bp-9]
    call gpu_draw_hline
   
    ; Draw left line
    mov cx, [bp-2]
    mov dx, [bp-4]
    mov si, [bp-8]
    mov al, [bp-9]
    call gpu_draw_vline
   
    ; Draw right line
    mov cx, [bp-2]
    add cx, [bp-6]
    dec cx
    mov dx, [bp-4]
    mov si, [bp-8]
    mov al, [bp-9]
    call gpu_draw_vline
   
    pop bp
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret

gpu_draw_line:
    push bp
    mov bp, sp
    sub sp, 16
   
    push bx
    push cx
    push dx
    push si
    push di
   
    ; Save color
    mov byte [bp-15], al
   
    ; Save endpoints
    mov word [bp-12], si
    mov word [bp-14], di
   
    ; Calculate dx = abs(x1 - x0)
    mov ax, si
    sub ax, cx
    test ax, ax
    jns .dx_positive
    neg ax
.dx_positive:
    mov word [bp-2], ax
   
    ; Calculate dy = abs(y1 - y0)
    mov ax, di
    sub ax, dx
    test ax, ax
    jns .dy_positive
    neg ax
.dy_positive:
    mov word [bp-4], ax
   
    ; Determine sx
    mov ax, 1
    cmp si, cx
    jge .sx_done
    neg ax
.sx_done:
    mov word [bp-6], ax
   
    ; Determine sy
    mov ax, 1
    cmp di, dx
    jge .sy_done
    neg ax
.sy_done:
    mov word [bp-8], ax
   
    ; err = dx - dy
    mov ax, word [bp-2]
    sub ax, word [bp-4]
    mov word [bp-10], ax
   
.loop:
    ; Plot pixel
    mov al, byte [bp-15]
    push cx
    push dx
    call gpu_set_pixel
    pop dx
    pop cx
   
    ; Check if done
    cmp cx, word [bp-12]
    jne .continue
    cmp dx, word [bp-14]
    je .done_line
   
.continue:
    ; e2 = 2 * err
    mov bx, word [bp-10]
    shl bx, 1
   
    ; if (e2 > -dy)
    mov ax, word [bp-4]
    neg ax
    cmp bx, ax
    jle .skip_x
   
    ; err -= dy
    mov ax, word [bp-10]
    sub ax, word [bp-4]
    mov word [bp-10], ax
   
    ; x0 += sx
    add cx, word [bp-6]
   
.skip_x:
    ; if (e2 < dx)
    cmp bx, word [bp-2]
    jge .skip_y
   
    ; err += dx
    mov ax, word [bp-10]
    add ax, word [bp-2]
    mov word [bp-10], ax
   
    ; y0 += sy
    add dx, word [bp-8]
   
.skip_y:
    jmp .loop
   
.done_line:
    pop di
    pop si
    pop dx
    pop cx
    pop bx
   
    mov sp, bp
    pop bp
    ret

; -------------------------------------
; Print string with color attribute
puts_with_color:
    push ax
    push bx
    push si
    push dx

.color_loop:
    lodsb
    test al, al
    jz .done
    mov ah, 0x09
    mov bh, 0
    mov cx, 1
    int 0x10

    push dx
    mov ah, 0x03
    mov bh, 0
    int 0x10
    inc dl
    mov ah, 0x02
    mov bh, 0
    int 0x10
    pop dx

    jmp .color_loop

.done:
    pop dx
    pop si
    pop bx
    pop ax
    ret

; -------------------------------------
; Print string
puts:
    push ax
    push bx
    push si

.loop:
    lodsb
    test al, al
    jz .done
    mov ah, 0x0E
    mov bh, 0
    int 0x10
    jmp .loop

.done:
    pop si
    pop bx
    pop ax
    ret

; -------------------------------------
; Data section
msg_welcome:     db 'Codename "Sytrus-harmor" OS v1.0 - [C.V.D.: 9/6/25]', ENDL
                 db 'Type "help" for available commands.', ENDL
                 db 'Early versions have many errors, bugs, and other such things!', ENDL
                 db 'Ascii test: abcdefghijklmnopqrstuvwxyz', ENDL, 0

msg_prompt:      db 'root/> ', 0
msg_newline:     db ENDL, 0
msg_unknown:     db 'Couldnt find command. Type "help" for help.', ENDL, 0
msg_rebooting:   db 'Restarting... ', ENDL, 0

msg_help_text:   db 'Available commands:', ENDL
                 db '  help    - Show this help', ENDL
                 db '  clear   - Clear the screen', ENDL
                 db '  echo    - Echo text to screen', ENDL
                 db '  beep    - Make a beep sound', ENDL
                 db '  test    - Simple graphics test', ENDL
                 db '  color   - Colorful text demo', ENDL
                 db '  pixel   - Pixel graphics demo', ENDL
                 db '  softgpu - Software GPU demonstration', ENDL
                 db '  reboot  - Restart the system', ENDL, 0

msg_test:        db 'Testing graphics mode...', ENDL, 0
msg_color_demo:  db 'Color text demonstration:', ENDL, 0
msg_pixel_demo:  db 'Entering pixel graphics mode...', ENDL, 0
msg_softgpu:     db 'Software GPU Demo - Press any key to return', ENDL, 0
msg_colored:     db 'This is colored text!', 0
msg_colored2:    db 'Different colors!', 0

; Command strings
cmd_help:        db 'help', 0
cmd_clear:       db 'clear', 0
cmd_echo:        db 'echo', 0
cmd_reboot:      db 'reboot', 0
cmd_beep:        db 'beep', 0
cmd_test:        db 'test', 0
cmd_color:       db 'color', 0
cmd_pixel:       db 'pixel', 0
cmd_softgpu:     db 'softgpu', 0

; Buffers
input_buffer:    times 80 db 0
edit_buffer:     times 80 db 0