A
A
Помогите пожалуйста переделать, чтобы каждый раз линии рисовались новым цветом.
Код:
; mousedr.asm
;Рисует на экране прямые линии, оканчивающиеся в позициях, которые указываются мышью.
;
.model tiny
.code
org 100h ; COM-файл.
.186 ; Для команжы shr cx, 3.
start:
mov ax, 12h
int 10h ; Видеорежим 640*480.
mov ax, 0 ; Инициализировать мышь.
int 33h
mov ax, 1 ; Показать курсор мыши.
int 33h
mov ax, 000Ch ; Установить обработчик событий мыши.
mov cx, 0002h ; Событие - нажатие левой кнопки.
mov dx, offset handler ; ES:DX - адрес обработчика.
int 33h
mov ah, 0 ; Ожидание нажатия любой клавиши.
int 16h
mov ax, 000Ch
mov cx, 0000h ; Удалить обработчик событий мыши.
int 33h
mov ax, 3 ; Текстоый режим.
int 10h
ret ; Конец программы.
; Обработчик событий мыши: при первом нажатии выводит точку на экран,
; при каждом дальнейшем вызове проводит прямую линию от предыдущей
; точки к текущей.
handler:
push 0A000h
pop es ; ES - начало видеопамяти.
push cs
pop ds ; DS - сегмент кода и данных этой программы.
push cx ; CX (X-координата) и DX(Y-координата)
push dx ; потребуются в конце.
mov ax, 2 ; Спрятать курсор мыши перед выводом на экран.
int 33h
cmp word ptr previous_X, -1 ; Если это первый вызов,
je first_point ; только вывести точку.
call line_bresenham ; Иначе - провести прямую.
exit_handler:
pop dx ; Восстановить CX и DX
pop cx
mov previous_X, cx ; и запомнить их как предыдущие
mov previous_Y, dx ; координаты.
mov ax, 1 ; Показать курсор мыши.
int 33h
retf ; Выход из обработчика - команда RETF.
first_point:
call putpixellb ; Вывод одной точки (при первом вызове).
jmp short exit_handler
; Процедура рисования прямой линии с использованием алгоритма Брезенхама.
; Вывод CX, DX - X, Y начальной точки.
; previous_X, previous_Y - X, Y начальной точки.
line_bresenham:
mov ax, cx
sub ax, previous_X ; AX = длина проекции прямой на ось X.
jns dx_pos ; Если AX отрицательный -
neg ax ; сменить его знак, причем
mov word ptr X_increment, 1 ; координата X при выводе
jmp short dx_neg ; прямой будет расти.
dx_pos: mov word ptr X_increment, -1 ; Иначе - уменьшаться.
dx_neg: mov bx, dx
sub bx, previous_Y ; BX = длина проекции прямой на ось Y.
jns dy_pos ; Если BX отрицательный -
neg bx ; сменить его знак, причем
mov word ptr Y_increment, 1 ; координата Y при выводе
jmp short dy_neg ; прямой будет расти.
dy_pos: mov word ptr Y_increment, -1 ; иначе - уменьшаться.
dy_neg:
shl ax, 1 ; Удвоить значения проекций,
shl bx, 1 ; чтобы избежать работы с полуцелыми числами.
call putpixellb ; Вывести первую точку (прямая рисуется от
; CX, DX к previous_X, previous_Y).
cmp ax, bx ; Если проекция на ось X больше, чем на Y,
jna dx_le_dy
mov di, ax ; DI будет указывать, в какую сторону мы
shr di, 1 ; отклонились от идеальной прямой.
neg di ; Оптимальное начальное значение DI:
add di, bx ; DI = 2 * dy - dx
cycle:
cmp cx, word ptr previous_X ; Основной цикл выполняется,
je exit_bres ; пока X не станет равное previous_X.
cmp di, 0 ; Если DI > 0,
jl fractlt0
add dx, word ptr Y_increment ; перейти к следующему Y
sub di, ax ; и уменьшить DI на 2 * dx.
fractlt0:
add cx, word ptr X_increment ; Следующий X (на каждом шаге).
add di, bx ; Увеличить на DI на 2 * dy.
call putpixellb ; Вывести точку. ;!!!!!
jmp short cycle ; Продолжить цикл.
dx_le_dy: ; Если проекция на ось Y больше, чем на X.
mov di, bx
shr di, 1
neg di ; Оптимальное начальное значение DI:
add di, ax ; DI = 2 * dx - dy.
cycle2:
cmp dx, word ptr previous_Y ; Основной цикл выполняется,
je exit_bres ; пока Y не станет равным previous_Y.
cmp di, 0 ; Если DI > 0,
jl fractlt02
add cx, word ptr X_increment ; перейти к следующему X
sub di, bx ; и уменьшить DI на 2 * dy,
fractlt02:
add dx, word ptr Y_increment ; Следующий Y (на каждом шаге).
add di, ax ; Увеличить DI на 2 * dy,
call putpixellb ; вывести точку,
jmp short cycle2 ; продолжить цикл.
exit_bres:
ret ; Конец процедуры.
; Процедура вывода точки на экран в режиме, использующем один бит для
; хранения одного пикселя.
; DX = строка, CX = столбец.
; Все регистры сохраняются.
putpixellb:
pusha ; Сохранить регистры.
xor bx, bx
mov ax, dx ; AX = номер строки.
imul ax, ax, 80 ; AX = номер строки x число байтов в строке.
push cx
shr cx, 3 ; CX = номер байта в строке.
add ax, cx ; AX = номер байта в видеопамяти.
mov di, ax ; Поместить его в SI и DI для команд
mov si, di ; строковой обработки.
pop cx ; CX снова содержит номер столбца.
mov bx, 0080h
and cx, 07h ; Последние три бита CX =
; остаток от деления на 8 = номер бита в байте
; считая справа налево.
shr bx, cl ; Теперь в BL установлен в 1 нужный бит.
lods es: byte ptr some_label ; AL = байт из видеопамяти.
;or ax, bx ; Установить выводимый бит в 1,
; Чтобы стереть пиксел с экрана, эту команду OR можно заменить на
not bx
and ax, bx
; или лучше инициализировать BX не числом 0080h, а числом FF7Fh и использовать
; только and
stosb ; И вернуть байт на место.
popa ; Восстановить регистры.
ret ; Конец.
previous_X dw -1 ; Предыдущая X-координата.
previous_Y dw -1 ; Предыдущая Y-координата.
Y_increment dw -1 ; Направление изменения Y.
X_increment dw -1 ; Направление изменения X.
some_label: ; Метка, используемая для переопределения
; сегмента-источника для lods с DS на ES.
end start