Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

RFpro.ru: Ассемблер? Это просто! Учимся программировать


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Чемпионы рейтинга экспертов в этой рассылке

Boriss
Статус: Академик
Рейтинг: 2366
∙ повысить рейтинг »
_Ayl_
Статус: Профессионал
Рейтинг: 1849
∙ повысить рейтинг »
vladisslav
Статус: 6-й класс
Рейтинг: 1227
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И ПО / Программирование / Assembler (Ассемблер)

Номер выпуска:1342
Дата выхода:24.05.2010, 21:00
Администратор рассылки:Лысков Игорь Витальевич, Модератор
Подписчиков / экспертов:269 / 63
Вопросов / ответов:1 / 1
IRC-канал по теме:#assembler

Вопрос № 178503: Уважаемые эксперты! Нужно написать программу - морфинг из куба в круг. DOS; TASM....



Вопрос № 178503:

Уважаемые эксперты! Нужно написать программу - морфинг из куба в круг. DOS; TASM.

Отправлен: 19.05.2010, 20:56
Вопрос задал: Доктор Ватсон, Посетитель
Всего ответов: 1
Страница вопроса »


Отвечает Лысков Игорь Витальевич, Модератор :
Здравствуйте, Доктор Ватсон.
Вот Вам морфинг квадрата в окружность.
Для квадрата достаточно хранить информацию только о половине стороны. Все остальное рисуется аналогично.
Код:

.model tiny, C
.386

R equ 80 ;радиус окружности = половине стороны квадрата
N equ 20 ;число итераций

POINT struc ;структура для хранения информации о меняющейся точке
X0 dd ? ;расстояние от центра точки на стороне квадрата
Xd dq ? ;приращение по Х для следующей итерации
Xi dq ? ;Х позиции точки при очередной итерации
POINT ends

.code
.startup
call FormPoints ;формируем информацию о точках половины стороны квадрата

mov ax, 0013h ; vga 320x200x256
int 10h

mov ax, 0a000h
mov es, ax ; es - с егмент видео

mov cx, N ;число итераций
call PrintFigure,0bh ;рисуем нулевую итерацию - исходную фигуру - квадрат
mov ah,0
int 16h ;для начала морфинга ждем нажатия на клавишу
FigureOff:
call PrintFigure,0 ;вытираем старую итерацию
call PrintFigure,0bh ;рисуем новую итерацию

call DELAY ;пауза

loop FigureOff ;рисуем N раз

WaitEscape:
mov ah, 0
int 16h ;выходим по Esc
cmp ah, 1
jne WaitEscape

;выход в DOS
mov ax, 0003h ; назад в текстовый режим
int 10h

mov ax, 4c00h ; bye-bye
int 21h

;Формируем массив с инфой обо всех точках
;для квадрата достаточно иметь инфу о половине стороны
FormPoints proc
local num:word, radius:word, count:word
lea di, pPoints ;будем хранить инфу сразу за программой
mov cx, R+2 ;число точек = радиусу+2, чтобы прорисовать углы
mov num, 0 ;начинаем от центра, num = расстояние по Х от центра
mov radius, R ;радиус
mov coun t, N ;число отрезков по Х
FormLoop:
fild num ;x
fst [POINT ptr di].X0 ;сохраним, как (float)x0
fst [POINT ptr di].Xi ;и как начальный x
fld st ;st(1) = st = x
fimul radius ;x*R
fild num ;x
fimul num ;x^2
fild radius ;R
fimul radius ;R^2
faddp ;x^2+R^2
fsqrt ;sqrt(x^2+R^2)
fdivp ;x*R/sqrt(x^2+R^2)
fsubp ;x-x*R/sqrt(x^2+R^2)
fidiv count ;deltaX = (x-x*R/sqrt(x^2+R^2))/count
fstp [POINT ptr di].Xd ;сохраним deltaX
add di, size POINT ;на следующую точку
inc num ;x=x+1
loop FormLoop ;по всем точкам
ret
FormPoints endp

;Рисуем очередную итерацию цветом colour
PrintFigure PROC colour:word
uses cx
local X1Num:word,Y1num:word,X2Num:word,Y2num:word,RR:word
mov RR, R ;радиус для вычислений
mov cx, R+1 ;число точек
lea di, pPoints ;адрес массива точек
mov bx, size POINT ;длина одного элемента

;получаем координаты первой точки
fld [POINT ptr di] .Xi ;Хi
;считаем Y=Xi*R/X0
cmp [POINT ptr di].X0, 0 ;для самой первой
jne PFDiv
fistp X1Num ;X1=Xi
mov Y1Num, R ;Y1=R
jmp PrintLoop
PFDiv:
fist X1Num ;X1=Xi
fimul RR ;Xi*R
fdiv [POINT ptr di].X0 ;Xi*R/X0
fistp Y1Num ;Y1=Xi*R/X0
PrintLoop:
push cx ;соханим счетчик
;получаем координаты второй точки
fld [POINT ptr di+bx].Xi ;Xi
fist X2Num ;X2=Xi
fimul RR ;Xi*R
fdiv [POINT ptr di+bx].X0 ;Xi*R/X0
fistp Y2Num ;Y2=Xi*R/X0

;выводим отрезок в правой половине верхней стороны квадрата
push colour
mov ax, 100
sub ax, Y2Num ;Y2 выше центра
push ax
mov ax, 160
add ax, X2Num ;X2 справа центра
push ax
mov ax, 100
sub ax, Y1Num ;Y1 выше центра
push ax
mov ax, 160
add ax, X1Num ;X1 справа центра
push ax
call line
add sp, 5*2

;выводим отрезок в левой половине верхней стороны квадрата
push colour
mov ax, 100
sub ax, Y2 Num ;Y2 выше центра
push ax
mov ax, 160
sub ax, X2Num ;X2 слева центра
push ax
mov ax, 100
sub ax, Y1Num ;Y1 вы ше центра
push ax
mov ax, 160
sub ax, X1Num ;X1 слева центра
push ax
call line
add sp, 5*2

;выводим отрезок в правой половине нижней стороны квадрата
push colour
mov ax, 100
add ax, Y2Num ;Y2 ниже центра
push ax
mov ax, 160
add ax, X2Num ;X2 справа центра
push ax
mov ax, 100
add ax, Y1Num ;Y1 ниже центра
push ax
mov ax, 160
add ax, X1Num ;X1 справа центра
push ax
call line
add sp, 5*2

;выводим отрезок в левой половине нижней стороны квадрата
push colour
mov ax, 100
add ax, Y2Num ;Y2 ниже центра
push ax
mov ax, 160
sub ax, X2Num ;X2 слева центра
push ax
mov ax, 100
add ax, Y1Num ;Y1 ниже центра
push ax
mov ax, 160
sub ax, X1Num ;X1 слева центра
push ax
call line
add sp, 5*2

;выводим отрезок в нижней половине левой стороны квадрата
;X и Y меняются местами
push colour
mov ax, 100
add ax, X2Num ;Y2 ниже центра
push ax
mov ax, 160
sub ax, Y2Num ;X2 слева центра
push ax
mov ax, 100
add ax, X1Num ;Y1 ниже центра
push ax
mov ax, 160
sub ax, Y1Num ;X1 слева центра
push ax
call line
add sp, 5*2

;выводим отрезок в верхней половине левой стороны квадрата
;X и Y меняются местами
push colour
mov ax, 100
sub ax, X2Num ;Y2 выше центра
push ax
mov ax, 160
sub ax, Y2Num ;X2 слева центра
push ax
mov ax, 100
sub ax, X1Num ;Y1 выше центра
push ax
mov ax, 160
sub ax, Y1Num ;X1 слева центра
push ax
call line
add sp, 5*2

;выводим отрезок в нижней половине правой стороны квадрата
;X и Y меняются местами
push colour
mov ax, 100
add ax, X2Num ;Y2 ниже центра
push ax
mov ax, 160
add ax, Y2Num ;X2 справа центра
push ax
mov ax, 100
add ax, X1Num ;Y1 ниже центра
push ax
mov ax, 160
add ax, Y1Num ;X1 справа центра
push ax
call line
add sp, 5*2

;выводим отрезок в верхней половине правой стороны квадрата
;X и Y меняются местами
push colour
mov ax, 100
sub ax, X2Num ;Y2 выше центра
push ax
mov ax, 160
add ax, Y2Num ;X2 справа центра
push ax
mov ax, 100
sub ax, X1Num ;Y1 выше центра
push ax
mov ax, 160
add ax, Y1Num ;X1 справа центра
push ax
call line
add sp, 5*2

;копируем правую точку (x2,y2) на место первой (x1,y1) для следующего отрезка
mov ax, X2Num
mov X1Num, ax
mov ax, Y2Num
mov Y1Num, ax

cmp colour, 0 ;после вытирания цветом 0 сдвигаем Xi на DeltaX
jne PFNext
fld [POINT ptr di].Xi
fsub [POINT ptr di].Xd
fstp [POINT ptr di].Xi ;Xi=Xi-Xd
PFNext:
add di, size POINT ;на следующую точку
pop cx ;счетчик циклов
dec cx ;loop не работает - слишком далеко
jcxz PFRet
jmp PrintLoop
PFRet: ;для последней точки подправим Xi
cmp colour, 0
jne PFRet1
fld [POINT ptr di].Xi
fsub [POINT ptr di].Xd
fstp [POINT ptr di].Xi
PFRet1:
ret
PrintFigure ENDP

;рисуем линию (x1,y1)-(x2,y2) цветом color
Line proc uses di bx, x1:word, y1:word, x2:word, y2:word, color:byte
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, a x ;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_x>delta_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 s t ;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 dx, 320 ;получим индекс начала строки экрана в сегменте экрана
imul dx ; для этого умножим на длину в байтах одной стоки
mov bx, ax ;сохраним bx=y=(y1+floor(incy*k*i))*320
;посчитаем X
mov ax, incx ;X меняется ровно на шаг приращения,
imul cx ; умноженному на индекс точки
add ax, x1 ;добавим абциссу начальной точки ax=x=x1+incx*i

add ax, bx ;сложим с индексом начала строки
mov di, ax ;будем адресовать через di

mov al, color ;цвет точки
mov es:[di], al ;рисуем!

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 dx, 320 ;получим индекс начала строки экрана в сегменте экрана
imul dx ; для этого умножим на длину в байтах одной стоки
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)

add ax, bx ;сложим с индексом начала строки
mov di, ax ;будем адресовать через di

mov al, color ;цвет точки
mov es:[di], al ;рисуем!

inc cx ;на следующую точку
cmp_i_y:
cmp cx, delta_y ;дошли до конца?
jl y_loop
Line_ret:
fistp i ;удалим из сопроцессора k
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

;пауза ~40мс. Под Windows весьма условно, скорее всего будет больше
time equ 4 ;число интервалов по 10мс
DELAY: pusha ;сохраним все регистры
mov ah,2dh ;сбросим "локальное" системное время (под nt+ все равно не поменяет)
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

pPoints label DWORD ;с этого адреса будем хранить данные о точках

end

-----
Удачи!

Ответ отправил: Лысков Игорь Витальевич, Модератор
Ответ отправлен: 22.05.2010, 08:31
Номер ответа: 261563
Украина, Кировоград
Тел.: +380957525051
ICQ # 234137952
Mail.ru-агент: igorlyskov@mail.ru
Абонент Skype: igorlyskov

Оценка ответа: 5
Комментарий к оценке:
Cпасибо!

Вам помог ответ? Пожалуйста, поблагодарите эксперта за это!
Как сказать этому эксперту "спасибо"?
  • Отправить SMS #thank 261563 на номер 1151 (Россия) | Еще номера »
  • Отправить WebMoney:

  • Оценить выпуск »
    Нам очень важно Ваше мнение об этом выпуске рассылки!

    Задать вопрос экспертам этой рассылки »

    Скажите "спасибо" эксперту, который помог Вам!

    Отправьте СМС-сообщение с тестом #thank НОМЕР_ОТВЕТА
    на короткий номер 1151 (Россия)

    Номер ответа и конкретный текст СМС указан внизу каждого ответа.

    Полный список номеров »

    * Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи. (полный список тарифов)
    ** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
    *** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.


    © 2001-2010, Портал RFpro.ru, Россия
    Авторское право: ООО "Мастер-Эксперт Про"
    Автор: Калашников О.А. | Программирование: Гладенюк А.Г.
    Хостинг: Компания "Московский хостер"
    Версия системы: 2010.6.15 от 18.05.2010

    В избранное