работа с мышкой

  • Автор темы A
  • Дата начала
#1
Помогите пожалуйста переделать, чтобы каждый раз линии рисовались новым цветом.
Код:
; 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
 
#2
все. я разобрался. вот, если кому нужно.
Код:
; 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:
inc color
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		; Вывод одной точки (при первом вызове).
mov 		ah, 2
mov 		dl, 07h			
int 		21h
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:
mov 		ah, 2
mov 		dl, 07h			
int 		21h
ret					; Конец процедуры.

; Процедура вывода точки на экран в режиме, использующем один бит для
; хранения одного пикселя.
; DX = строка, CX = столбец.
; Все регистры сохраняются.

putpixellb:
pusha					; Сохранить регистры.
mov ah,0ch
mov bh,0
mov al,[color]
int 10h

popa					; Восстановить регистры.
ret					; Конец.

previous_X			dw	-1		; Предыдущая X-координата.
previous_Y			dw	-1		; Предыдущая Y-координата.
Y_increment			dw	-1		; Направление изменения Y.
X_increment			dw	-1		; Направление изменения X.
color db 10
some_label:						; Метка, используемая для переопределения
; сегмента-источника для lods с DS на ES.
end	start