Консультация № 179352
29.06.2010, 14:31
0.00 руб.
0 5 0
Уважаемые эксперты, благодаря Вам, научился рисовать прямые линии под произвольным углом. А как вывести одинаковые движущиеся прямоугольные маски, или спрайты, под углом от 0 до 180? При этом одна координата (х1, y1) постоянна, а другая координата (х2, y2) может меняться. В приложении программа, которая выводит невидимую маску чёрного цвета (цвета фона), которая может перемещаться с помощью управляющих клавиш, в центре которой сходятся две прямые линии. Раз маска может перемещаться, то и прямые линии выводятся под разными углами. Прямые выводятся из противоположных краёв экрана – постоянная координата (х1, y1) для каждой прямой, и сходятся в центре бесцветной маски – меняющаяся координата (х2, y2). У меня, правда, почему-то эти прямые сильно мерцают, возможно, что из-за выбранного режима.
Вопрос, как вывести вместо этих двух прямых движущиеся прямоугольные спрайты, размером, например, 5х10, которые так же сходились бы в одном месте.
И ещё вопрос: я привязал координаты (х2, y2) к строке и колонке маски командами mov ax, [row], mov ax, [column], а можно ли как-то привязать эти координаты через смещение маски, вроде mov bx,offset Msk. У меня последний вариант не получался: линия выводилась, но в другую сторону и не двигалась.
Заранее спасибо.


Приложение:
locals @@
.model tiny, C
.386
.code
.startup
mov ax, 0012h ;vga 640х480х16
int 10h

mov dx, 03CEh ;индексный порт графического контроллера
mov ax, 0F01h ;разрешение установки/сброса
out dx, ax

mov ax, 0a000h
mov es, ax
MainLoop:
call Draw,offset msk ;адрес маски
lines:
mov ax, [column]
add ax,2
mov x2,ax
mov ax, [row]
add ax,2
mov y2,ax

call line, 20,460, x2, y2, 0Bh ;вывод 1-ой линии
call DELAY ;задержка
call line, 20,460, x2, y2, 0h ;стираем
call line, 640,460, x2, y2, 0Bh ;вывод 2-ой линии
call DELAY ;задержка
call line, 640,460, x2, y2, 0h ;стираем
mov ah,1
int 16h
jz MainLoop
mov ah, 0 ;проверяем на код клавиши
int 16h
cmp ah, 1 ;по Esc выходим
je Exit

cmp ah, 4bh ;стрелка влево
je left
cmp ah, 4dh ;стрелка вправо
je right
cmp ah, 48h ;стрелка вверх
je up
cmp ah, 50h ;стрелка вниз
je down
jne MainLoop

left:
call Draw,offset black
sub column,10
jmp MainLoop

right:
call Draw,offset black
add column,10
jmp MainLoop

up:
call Draw,offset black
sub row,10
jmp MainLoop

down:
call Draw,offset black
add row,10
jmp MainLoop

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Exit:
mov ax, 0003h ;восстановим текстовый режим
int 10h

mov ax, 4c00h
int 21h

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Draw proc maska:word
; вычислить номер байта в видеопамяти
mov ax, [row] ;AX = строка
mov bx, 80
mul bx ;AХ = АХ * 80
mov di, ax ;сохранить адрес начала строки в di
mov ax, [column]
mov cl, al
shr ax, 3 ;AX = номер байта в строке
add di, ax ;DI = номер байта в видеопамяти
and cl, 7 ;вычислить номер бита в байте
mov ch, 80h
shr ch, cl
mov dx, 03CEh ;индексный порт графического контроллера
mov si,[maska]
mov bl,[si] ; число строк
inc si
mov cl,[si] ; число столбцов
inc si
@@next_row:
push di ; сохраняем смещение начала маски в видеобуфере
push cx ; маска пикселя и число столбцов
@@next_pixel:
mov ah, [si] ;цвет
mov al, 0 ;регистр установки/сброса
out dx, ax ;цвет
mov al, 8 ;битовая маска
mov ah, ch ;записать в битовую маску нули всюду, кроме
out dx, ax ;бита, соответствующего выводимому пикселю
xchg es:[di],ah ;заполнить регистры-защелки и вывести на экран пиксель
inc si ;к следующему байту маски
ror ch,1 ;маска для следующего пикселя
adc di,0
@@2:
dec cl
jnz @@next_pixel
pop cx ; восстанавливаем маску
pop di
add di,80 ; к следующей строке
dec bl
jnz @@next_row
ret
Draw endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;рисуем линию (x1,y1)-(x2,y2) цветом color
Line proc uses di bx, x1:word, y1:word, x2:word, y2:word, color:word
pusha
local i:word, \ ;для работы со сопроцессором
delta_x:word, \ ;длина проекции на ось абсцисс
delta_y:word, \ ;длина проекции на ось ординат
incx:word, \ ;приращение по X
incy:word ;приращение по Y

;определим длину проекции на ось абсцисс и шаг по оси X
mov ax, x2
sub ax, x1 ;ax=x2-x1;

;определим шаг по X (+1 если вперед, -1 если назад, 0 если не меняется)
mov incx, 0 ;пусть incx=0
test ax, ax ;ax=delta_x
jz set_delta_x ;не меняется
jg set_x_1 ;вперед?
dec incx ;назад, значит incx=-1
neg ax ;найдем ax=abs(delta_x)
jmp set_delta_x ;на сохранение
set_x_1:
inc incx ;вперед, значит incx=1;
set_delta_x:
mov delta_x, ax ;delta_x = abs(x2-x1)

;определим длину проекции на ось ординат и шаг по оси Y
mov ax, y2
sub ax, y1 ;ax=y2-y1;

;определим шаг по Y (+1 если вперед, -1 если назад, 0 если не меняется)
mov incy, 0 ;пусть incy=0
test ax, ax ;ax=delta_y
jz set_delta_y ;не меняется
jg set_y_1 ;вперед?
dec incy ;назад, значит incy=-1
neg ax ;найдем ax==abs(delta_y)
jmp set_delta_y ;на сохранение
set_y_1:
inc incy ;вперед, значит incy=1;
set_delta_y:
mov delta_y, ax ;delta_y=abs(y2-y1)

;определим большее из проекций как основное направление
cmp ax, delta_x ;ax=delta_y
jge from_y ;y будет основным
cmp delta_x, 0 ;проверим, чтобы не было delta_x=0 (для точки),
jz Line_ret ; иначе будет деление на 0
;delta_xdelta_y && delta_x!=0
;основное направление - по оси X
fild delta_y
fidiv delta_x ;st=k=(float)(delta_y/delta_x)

;for (int i=0;i<delta_x;i++)
xor cx, cx ;cx=i
jmp cmp_i_x ;на проверку i<delta_x
x_loop: ;тело цикла
mov i, cx ;запишем переменную цикла в память (для сопроцессора)
fld st ;st=st(1)=k
fimul i ;st=k*i
fimul incy ;st=incy*k*i
call floor ;округлим до целого в большую сторону
fistp i ;сохраним в переменной
mov ax, i ;относительный номер строки на экране
add ax, y1 ;добавим до ординаты начальной точки
mov bx, ax ;сохраним bx=y=(y1+floor(incy*k*i))
;посчитаем X
mov ax, incx ;X меняется ровно на шаг приращения,
imul cx ; умноженному на индекс точки
add ax, x1 ;добавим абциссу начальной точки ax=x=x1+incx*i

call PutPixel, ax, bx, color

inc cx ;на следующую точку
cmp_i_x:
cmp cx, delta_x ;дошли до конца?
jl x_loop
jmp Line_ret ;на выход

from_y: ;вдоль оси Y
fild delta_x
fidiv delta_y ;st=k=(float)(delta_x/delta_y)

;for (int i=0;i<delta_y;i++)
xor cx, cx ;cx=i
jmp cmp_i_y ;на проверку i<delta_y
y_loop: ;тело цикла
mov ax, incy ;Y меняется ровно на шаг приращения,
imul cx ;умноженному на индекс точки
add ax, y1 ;добавим абциссу начальной точки ax=y=y1+incy*i
mov bx, ax ;сохраним bx=y=(y1+incy*i)*320
;посчитаем X
mov i, cx ;запишем переменную цикла в память (для сопроцессора)
fld st ;st=st(1)=k
fimul i ;st=k*i
fimul incx ;st=incx*k*i
call floor ;округлим до целого в большую сторону
fistp i ;сохраним в переменной
mov ax, i ;относительный номер строки на экране
add ax, x1 ;ax=x=x1+floor(incx*k*i)

call PutPixel, ax, bx, color

inc cx ;на следующую точку
cmp_i_y:
cmp cx, delta_y ;дошли до конца?
jl y_loop
Line_ret:
fistp i ;удалим из сопроцессора k
popa
ret
Line endp

;округление до целого
floor proc
local CtrlWordOld:word, CtrlWordNew:word
fstcw CtrlWordOld ;сохраним управляющее слово
fclex ;сбросим исключения
mov CtrlWordNew,0763h ;установим необходимое значение управляющего слова
fldcw CtrlWordNew ;загружаем управляющее слово
frndint ;округляем st до целого
fclex ;сбросим исключения
fldcw CtrlWordOld ;восстановим старое управляющее слово
ret
floor endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
PutPixel proc ccolumn:word, rrow:word, colour:word
uses cx
mov cx, ccolumn
mov ax, rrow ;AX = строка
mov bx, 80
mul bx ;AХ = АХ * 80
mov di, ax ;сохранить адрес начала строки в di
mov ax, cx
shr ax, 3 ;AX = номер байта в строке
add di, ax ;DI = номер байта в видеопамяти
and cx, 7 ;остаток от деления на 8
mov ch, 80h
shr ch, cl
mov dx, 03CEh ;индексный порт графического контроллера
mov ax, colour
shl ax, 8 ;регистр 00h: регистр установки/сброса
out dx, ax ;АН = цвет
mov al, 8 ;битовая маска
mov ah, ch ;записать в битовую маску нули всюду, кроме
out dx, ax ; бита, соответствующего выводимому пикселю
mov al, byte ptr es:[di] ;заполнить регистры-защелки
mov byte ptr es:[di],ah ; вывод на экран
ret
PutPixel endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
time equ 40 ;число интервалов по 10мс
DELAY: pusha
mov ah,2dh ;сбросим "локальное" системное время
xor cx,cx
xor dx,dx
int 21h

dl2: mov ah,2ch
int 21h ;читаем время
;считаем сотни мс
mov al,100
mul dh ;секунды умножаем на 100 -> ax = количество интервалов по 10мс
xor dh,dh ;dx - число сотых
xchg ax,dx ;поменяем местами
mov cl,10
div cl ;ax = количество интервалов по 10мс из сотых
add ax,dx ;складываем с количеством из секунд
cmp ax,time ;сравним с ожидаемым интервалом
jl dl2 ;ждем, если меньше
popa ;восстановим все регистры
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.data
column dw 320
row dw 240

Msk db 3,3 ; размер маски в точках: строк, столбцов
db 0,0,0
db 0,0,0
db 0,0,0

black db 3,3 ; размер маски в точках: строк, столбцов
db 0,0,0
db 0,0,0
db 0,0,0
END

Обсуждение

давно
Старший Модератор
31795
6196
30.06.2010, 10:06
общий
Adsorores:
Мерцание у Вас в этих строчках образовалось:
Код:
       call	line, 20,460, x2, y2, 0Bh  ;вывод 1-ой линии
call DELAY ;задержка
call line, 20,460, x2, y2, 0h ;стираем
call line, 640,460, x2, y2, 0Bh ;вывод 2-ой линии
call DELAY ;задержка
call line, 640,460, x2, y2, 0h ;стираем

1)нарисуйте все линии;
2)увеличте задержку визуального отображения;
3)сотрите все линии.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
30.06.2010, 15:10
общий
Спасибо, исправил, мерцание прекратилось. Но вопрос вывода прерывистой линии в виде спрайтов остался.
давно
Старший Модератор
31795
6196
01.07.2010, 16:30
общий
Adsorores:
Честно говоря я так и не понял, что Вы хотите получить?
Цитата: 289969
Но вопрос вывода прерывистой линии в виде спрайтов остался.

Вам нужно выводить, что-то вроде пунктирной(прерывистой) линии?
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
01.07.2010, 20:15
общий
Зенченко Константин Николаевич:
Совершенно верно, мне нужна не прямая, а прерывистая, пунктирная. Но мои линии имеют толщину в 1 пиксел, а мне нужно толще, потому и нужны спрайты в виде прямоугольников. Нужно вывести более одного спрайта с произвольным пробелом между ними, скорость неважна. Я могу вывести такие спрайты, но они могут двигаться только вертикально и горизонтально, но не под любым углом, т.к. в этом случае нужно использовать алгоритм Брезенхема. Под любым углом я могу рисовать с помощью этого алгоритма только тонкие линии, в пиксел.
Мне нужно вместо каждой прямой в приведённой программе вывести по 2 или более движущихся спрайта размером, например, 5х10.
давно
Старший Модератор
31795
6196
01.07.2010, 21:01
общий
Adsorores:
Когдато у меня были исходники Turbo Pascal. Сейчас их уже нет.
Тогда я разбирался с рисованием пунктира функция:
SetLineStyle (процедура) (модуль Graph) Устанавливает текущий стиль линии.

Объявление: Procedure SetLineStyle(LineStyle : Word; Pattern : Word; Thickness : Word);

Режим: Real, Protected

Замечания: Влияет на все линии, рисуемые процедурами Line, LineTo, Rectangle, DrawPoly, Arc и подобными.
Линии могут быть нарисованы следующими предопределенными стилями:
SolidLn (непрерывная) (0)
DottedLn (точечная) (1)
CenterLn (средняя) (2)
DashedLn (штриховая) (3)
UserBitLn (устанавливаемая пользователем) (4)

Если в процедуру SetLineStyle переданы недопустимые параметры, то в переменной GraphResult возвращается значение grError и текущие установки линий не будут изменены.

Параметр LineStyle - это значение от SolidLn до UserBitLn (0 .. 4). Параметр Pattern игнорируется, если LineStyle не равняется UserBitLn. Параметр Thickness может быть равен NormWidth (1) или ThickWidth (3).

Когда LineStyle равняется UserBitLn, строка выводится с использованием 16-разрядного шаблона, определяемого параметром Pattern. Например, если Pattern = $AAAA, то 16-разрядный шаблон выглядит так:

1010101010101010 { <-- Для толщины = NormWidth }
1010101010101010 { <-- Для толщины = ThickWidth }
1010101010101010
1010101010101010


Толщину не помню, нужно будет посмотреть сгенерированный код, а пунктир рисовался так:
Режим UserBitLn пользователь в 16-ти битах описывал вид пунктира: к примеру: 0110 0011 1100 0110
Загружалось это значение в регистр и потом крутилось командами:
Код:
MOV ax,StyleLine
ROR AX,1
MOV StyleLine,AX
JNC noPixelWrite
PixelWtite:
. . .
noPixelWrite:
. . .

Что-то вроде этого.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Форма ответа