[org 100h]
[segment .text]

; alokovani pameti

		mov       AX, CS		; nejprv alokuju pamet
		mov       ES, AX
		mov       AH, 4Ah
		mov       BX, 4000              ; 64000 / 16 = 4000 paragrafu
		int       21h
		jnc       _stinram              ; alokovano?
		ret                             ; ne, tak konec

_stinram:       mov       AX, CS                ; jo, tak nastavim promenou stinram
		add       AX, 4096
		mov       [stinram], AX

; pritomnost mysi

		mov       AX, 0			; kouknem na mysku
		int       33h
		test      AX, AX                ; tak je tu?
		jnz       _grmod                ; jo je
                ret                             ; neni, tak konec

; puvodni graf. mod

_grmod:         mov       AH, 0Fh               ; zjistime puvodni graf. mod
                int       10h
	        mov	  [grmod], AL	        ; ulozime ho
		mov       AX, 0013h		; nastavim 320x200x256
		int       10h

; nastaveni mysi

		mov       AX, 7			; max. a min. souradnice
		xor       CX, CX
		mov       DX, 321-2*R
		int       33h
		inc       AX
		mov       DX, 201-2*R
		int       33h

; cteni prikazoveho radku

		mov       SI, 93		; nacteme command line
		mov       BX, filename          ; potrebujeme nastavit jmeno
		mov       CX, 8                 ; soubor ma max 8 znaku jmena a koncovku .tga
_nextchar:	lodsb                           ; nactu znak
		cmp       AL, ' '               ; je to prazdny?
		jz        _finish               ; jo, tak to bude uz cely jmeno
		mov       [BX], AL              ; ne tak pripiseme znak jmena
		inc       BX                    ; a nastavime na dalsi znak
		loop      _nextchar             ; a znova
_finish:        mov       EAX, '.tga'           ; pripiseme koncovku
		mov       [BX], EAX

; pokus o otevreni souboru

		mov       AX, 3d00h		; budeme otevirat jen pro cteni
		mov       DX, filename          ; tady mame nacteny jmeno
		int       21h
		jnc       _fileopen             ; podarilo se otevrit?
		ret                             ; ne, tak konec (asi spatny jmeno)
_fileopen:      mov       BX, AX                ; jo, tak ulozime handle souboru

; cteni ze souboru

		mov       AX, 4200h		; nastavime sluzbu, v BX je ulozen handle, od zacatku
		xor       CX, CX
		mov       DX, 18                ; offset 18, tam zacina paleta
		int       21h

		push      DS			; budeme nahravat paletu ze souboru
		mov       AX, [stinram]         ; zatim si to dame do virtual screenu, protoze pak to stejne smazem
		mov       DS, AX

		xor       DX, DX
		mov       AH, 3fh               ; nacteme celou paletu do stinove RAM
		mov       CX, 768
		int       21h

		xor       AX, AX
		xor       SI, SI
		mov       CX, 256               ; ma to 256 barev

_palnext:	mov       DX, 03c8h             ; port adres grafarny
                mov       AL, AH                ; index barvy
		out       DX, AL
		inc       DX                    ; port data grafarny
		inc       AH

                mov       AL, [DS:SI+2]         ; R slozka vynasobena 4
		shr       AL, 2                 ; delim 4 protoze to je inteligentne ulozeny ve 256
		out       DX, AL
		push      AX                    ; ulozime AH (index barvy)
		lodsw                           ; nactem do AH G a do AL B
		push      AX                    ; ulozime AH (B)
		mov       AL, AH                ; a odesleme G
		shr       AL, 2
		out       DX, AL
                pop       AX                    ; obnovime AH (B)
		shr       AL, 2
		out       DX, AL                ; a odesleme
                inc       SI
                pop       AX                    ; obnovim AH (index barvy)
		loop      _palnext              ; nastavime dalsi barvu

; cteni obrazku do stinove video RAM

		xor       DX, DX
		mov       AH, 3fh
		mov       CX, 64000
		int       21h

		mov       AH, 3eh		; a uzavreme soubor
		int       21h
		pop       DS                    ; a obnovime DS

		call      MAPbuild              ; zavolame proceduru, ktera vytvori mapu lupy

; cteni polohy mysi

_prekresli:	mov       AX, 3h		; nacteme polohu mysi
		int       33h
		mov       BX, CX                ; ulozime si x do BX
		push      BX                    ; ulozime si souradnice
		push      DX

		call      _uloz_vyrez           ; musime si ulozit vyrez, ktery budeme lupit
		call      _lupa                 ; vylupime
		call      _flip                 ; a prekreslime, co mame ve virt scr do graf. pam

_kontrola:	mov       AX, 0bh               ; nacteme relativni zmenu
		int       33h
		test      CX, CX                ; pohnul uzivatel mysi v X?
		jnz       _pohnul               ; jo tak to musime prekreslit
		test      DX, DX                ; pohnul uzivatel mysi v Y?
		jnz       _pohnul               ; jo, prekreslit

                mov       ah, 6
                mov       dl, 0ffh
                int       21h			; zmackl uzivatel klavesu?
                jnz       _konec                ; jo tak budeme koncit

		jmp       _kontrola             ; uzivatl nic nezmack ani nepoh mysi, tak se podivame znova, jestli neco neudelal

_pohnul		pop       DX                    ; uzivatel pohnul mysi, tak vratime souradnice, co jsme lupili
		pop       BX
		call      _obnov_vyrez          ; prekreslime zpet ten vyrez co sme si ulozili
		jmp       _prekresli            ; znova prekreslime lupu

_konec:		pop       DX                    ; uzivatel neco zmacknul, tak si vybereme registry, co sou ulozeny
		pop       BX

                xor       AH, AH                ; obnovime puvodni grafickej rezim
		mov       AL, [grmod]
		int       10h
		ret				; a ukoncime program

; okopirovani stinove video RAM do video RAM

_flip:		push      DS                    ; prekreslime virt screen do video ram
      		push      word 0A000h
		pop       ES                    ; ES zacatek video ram
		mov       DS, [stinram]         ; DS zacatek virt screen
		xor       DI, DI
		xor       SI, SI
		mov       CX, 32000             ; pekne to presypeme po dw
		rep       movsw                 ; mame toho 32000
		pop       DS                    ; obnovime DS
		ret

; ulozeni vyrezu z originalniho obrazku do promenne vyrez, od souradnice BX, DX

_uloz_vyrez:	push      DS
		push      DX
		push      BX
		mov       SI, DX                ; zjistime zacatek vyrezu
		shl       DX, 8                 ; 2^8 = 256
		shl       SI, 6                 ; 2^6 = 64
		add       SI, DX                ; y*320
		add       SI, BX                ; +x

                push      DS                    ; do ES dame data segment
                pop       ES
                push      word [stinram]        ; do DS zacatek virt screenu
                pop       DS
		mov       DI, vyrez             ; budeme presypavat do promenny

		mov       CX, 2*R-1             ; velikost mapy y
_uloz_dalsi:	push      CX
		mov       CX, 2*R-1             ; velikost mapy x
		rep       movsb                 ; presypeme po bytech protoze nevime, jak to bude velky
		add       SI, 321-2*R           ; skocime na dalsi radek ve virt screenu
		pop       CX
		loop      _uloz_dalsi           ; a deme na dalsi radek
		pop       BX
		pop       DX
		pop       DS
		ret

; obnoveni puvodniho obrazku pomoci obsahu promenne vyrez

_obnov_vyrez:	push      DS
		push      DX
		push      BX
		mov       DI, DX                ; zjistime zacatek vyrezu
		shl       DX, 8                 ; 2^8 = 256
		shl       DI, 6                 ; 2^6 = 64
		add       DI, DX                ; y*320
		add       DI, BX                ; +x

		push      word [stinram]        ; z promene vyrez obnovime do stinove RAM v ES
		pop       ES
		mov       SI,vyrez

		mov       CX, 2*R-1             ; to samy jako pri ukladani
_obnov_dalsi:	push      CX
		mov       CX, 2*R-1
		rep       movsb
		add       DI, 321-2*R
		pop       CX
		loop      _obnov_dalsi
		pop       BX
		pop       DX
		pop       DS
		ret

; efekt lupy - z vyrezu do stinove video RAM

_lupa:		push      DX
		push      BX

		mov       DI, DX                ; zjistime zacatek vyrezu
		shl       DX, 8                 ; 2^8 = 256
		shl       DI, 6                 ; 2^6 = 64
		add       DI, DX                ; y*320
		add       DI, BX                ; +x

		push      word [stinram]        ; do ES zacatek virt screenu
		pop       ES
		mov       SI, map
		mov       BX, vyrez

		mov       CX, 2*R-1
_lupa_y:	push      CX
		mov       CX, 2*R-1
_lupa_x:	lodsw                           ; nacteme z mapy offset
		add       BX, AX                ; pripocteme ho - kam se ma posunout
		mov       AL, [DS:BX]           ; zjistime ten pixel
		stosb                           ; a zapiseme ho
		loop      _lupa_x
		add       DI, 321-2*R           ; a udelam to pro dalsi radku
		pop       CX
		loop      _lupa_y
		pop       BX
		pop       DX
		ret

; rutina pro vytvoreni mapy lupy

MAPbuild	mov       AX, DS		;  tak tohle sem uspesne rejpnul z netu
		mov       ES, AX
	        mov       BX, 1-R
		mov       SI, R*R
		mov       DI, map
		mov       BP, -2*R*(R-1)

nok		mov       CX, 1-R
nol		mov       AX, CX
		imul      CX
		push      AX
		mov       AX, BX
		imul      BX
		pop       DX
		add       AX, DX
		cmp       AX, SI
		jc        nor
		mov       AX, BX
		push      CX
		jmp       short nos
nor		mov       DX, 65536*(M-N)/M/N
		mul       DX
		mov       AX, DX
		add       AX, R*R/M
		push      AX
		imul      CX
		idiv      SI
		mov       DX, AX
		pop       AX
		push      DX
		imul      BX
		idiv      SI
nos		mov       AH, 2*R-1
		imul      AH
		pop       DX
		add       AX, DX
		push      AX
		sub       AX, BP
		stosw
		pop       BP
		inc       CX
		cmp       CL, R
		jl        nol
		inc       BX
		cmp       BL, R
		jl        nok
		ret


R	  equ             31                    ; parametry lupy
N	  equ             2
M         equ             3
filename  db              '        '            ; jmeno souboru
grmod     db              0                     ; puvodni grafiky mod
vyrez     resb            (2*R-1)*(2*R-1)       ; ulozeni vyrezu pred zvetsenim
map       resw            (2*R-1)*(2*R-1)       ; vlastni mapa, ze ktere pocitame zvetseni
stinram   dw              0                     ; zacatek virtual screenu
