Вопрос № 178512: Уважаемые эксперты! Нужно написать программу - "Калейдоскоп" т.е. на экране появляются меняющиеся симметричные разноцветные узоры(квадраты, прямоугольники, круги и т.д.), можно во весь экран, а можно отдельно в какой-то области экрана. DOS...
Вопрос № 178758: Здравствуйте, помогите разобраться с процедурой. Т.е. откомментируйте каждую строчку как можно более простым языком (с какой целью это делаем и что получаем), и по возможности изобразите на рисунках (рисовать можно от руки, сфотограффировать, и вылож...
Вопрос № 178512:
Уважаемые эксперты! Нужно написать программу - "Калейдоскоп" т.е. на экране появляются меняющиеся симметричные разноцветные узоры(квадраты, прямоугольники, круги и т.д.), можно во весь экран, а можно отдельно в какой-то области экрана. DOS, TASM.
m
ov ax, 0a000h mov es, ax ;сегмент видеопамяти для графики
MainLoop: ;основной цикл call GetFigure ;формируем координаты и цвет call SetFigure, Color;выводим call DELAY ;ждем call SetFigure, 0 ;вытираем mov ah, 1 int 16h ;проверяем, было ли нажатие jz MainLoop ;не было - продолжаем рисовать mov ah, 0 int 16h ;если было, то считываем cmp ah, 1 ;выходим тлько по Esc jnz MainLoop
mov ax, 0003h ;назад в текстовый режим int 10h
mov ax,
4c00h ;выход int 21h
Random PROC ;вычисляем псевдослучайную величину mov ax, RandomSeed mov dx, 4Dh inc ax jz Rnd_1 mul dx Rnd_1: sub ax, dx adc ax, 0 mov RandomSeed, ax ret Random ENDP
Rnd proc base:word ;вычисляем псевдослучайную величину в пределах [0,base-1] call Random xor dx, dx div base mov ax, dx ;остаток от деления ret Rnd endp
GetFigure proc ;строим данные для очеред
ной фигуры call Rnd, 3 ;случайная величина 0-2 mov FigureType, ax ;тип фигуры mov bx, ax shl bx, 1 call FormFigure[bx] ;в зависимости от типа задаем данные call Rnd, 255 ;сл величина в пределах 0-254 inc ax ;1-255 mov color, ax ;цвет в пределах 1-255 ret GetFigure endp
SetFigure proc colour:word ;выводим фигуру цветом colour mov bx, FigureType shl bx, 1 call DrawFigure[bx], colour ;в зависимости от ее типа ret SetFigure endp
FormCircle proc ;окружность - задаем центр и радиус ;причем находим такой радиус, чтобы окружность была целиком на экране call Rnd, 320 mov x1, ax ;0<=x1<320 ;определим, к какой стороне ближе, к левой или правой cmp ax, 160 jb save_x sub ax,
320 neg ax save_x: mov x2, ax ;x2 = минимальное расстояние до левой/правой сторон call Rnd, 200 mov y1, ax ;0<=y1<200 ;определим, к какой стороне ближе, к верхней или нижней cmp ax, 100 jb cmp_x sub ax, 200 neg ax cmp_x: ;ax = минимальное расстояние до верхней/нижней сторон cmp ax, x2 ;найдем минимальное расстояние до боковых сторон jbe GetRadius mov ax, x2 GetRadius: call Rnd, ax ;найдем радиус, не
больший минимального расстояния mov x2, ax ;сохраним радиус ret FormCircle endp
;рисуем четыре симметричных прямоуголь
ника в четырех квадрантах DrawRectangle proc col:word call OneRectangle, x1, y1, x2, y2, col ;симметрия относительно середины по оси Х mov di, 320 sub di, x1 mov bx, 320 sub bx, x2 call OneRectangle, di, y1, bx, y2, col ;симметрия относительно середины по оси Y mov di, 200 sub di, y1 mov bx, 200 sub bx, y2 ;симметрия относительно середины экрана call OneRectangle, x1, di, x2, bx, col mov ax, 320 sub ax, x1 mov dx, 320 sub dx, x2 call OneRectangle,
ax, di, dx, bx, col ret DrawRectangle endp
;рисуем один прямоугольник, как четыре линии, соединяющие вершины OneRectangle proc Rx1:word, Ry1:word, Rx2:word, Ry2:word, Rcol:word call Line, Rx1, Ry1, Rx2, Ry1, Rcol call Line, Rx2, Ry1, Rx2, Ry2, Rcol call Line, Rx1, Ry2, Rx2, Ry2, Rcol call Line, Rx1, Ry1, Rx1, Ry2, Rcol ret OneRectangle endp
;рисуем четыре симметричных треугольника в четырех квадрантах DrawTri
angle proc col:word call OneTriangle, x1, y1, x2, y2, x3, y3, col ;симметрия относительно середины по оси Х mov di, 320 sub di, x1 mov bx, 320 sub bx, x2 mov si, 320 sub si, x3 call OneTriangle, di, y1, bx, y2, si, y3, col ;симметрия относительно середины по оси Y mov di, 200 sub di, y1 mov bx, 200 sub bx, y2 mov si, 200 sub si, y3 call OneTriangle, x1, di, x2, bx, x3, si, col ;симметрия относительно середины экрана mov ax, 320 sub ax,
x1 mov cx, 320 sub cx, x2 mov dx, 320 sub dx, x3 call OneTriangle, ax, di, cx, bx, dx, si, col ret DrawTriangle endp
;рисуем один треугольник, как три линии, соединяющие вершины OneTriangle proc Tx1:word, Ty1:word, Tx2:word, Ty2:word, Tx3:word, Ty3:word, Tcol:word call Line, Tx1, Ty1, Tx2, Ty2, Tcol call Line, Tx2, Ty2, Tx3, Ty3, Tcol call Line, Tx1, Ty1, Tx3, Ty3, Tcol ret OneTriangle endp
;рисуем четыре
симметричных окружностей в четырех квадрантах DrawCircle proc col:word call OneCircle, x1, y1, col ;симметрия относительно середины по оси Х mov si, 320 sub si, x1 call OneCircle, si, y1, col ;симметрия относительно середины по оси Y mov bx, 200 sub bx, y1 call OneCircle, x1, bx, col ;симметрия относительно середины экрана call OneCircle, si, bx, col ret DrawCircle endp
;рисуем окружность, как набор точек по формулам x=Cx1+X2*cos(A), y=Cy1+X2*sin(A) OneCircle proc Cx1:word,
Cy1:word, Ccol:word local xx:word, yy:word, angle:word mov cx, 360 ;рисуем точки через каждый градус mov angle, 0 ;начинаем с 0 градусов CircleLoop: fldpi ;пи fimul angle ;пи*угод fidiv c180 ;A=пи*угод/180 - угол в радианах fsincos ;st=cos, st(1)=sin fild x2 ;радиус R=x2 fmulp ;x2*cos(A) fistp xx ;xx=x2*cos(A) mov ax, Cx1 add xx, ax ;xx=Cx1+x2*cos(A) fild x2 ;радиус R=x2 fmul
p ;x2*sin(A) fistp yy ;yy=x2*sin(A) mov ax, Cy1 add yy, ax ;yy=Cy1+x2*cos(A) ;преобразуем в экранные координаты mov ax, 320 ;число точек в строке mul yy ;строка*320 add ax, xx ;строка*320+позиция в строке mov di, ax ;адрес точки mov ax, Ccol ;цвет mov es:[di], al ;выводим inc angle ;на следующий угол loop CircleLoop ;360 раз ret OneCircle endp
;рисуем линию (x1,y1)-(x2,y2) цветом _color Line proc uses di bx, _x1:word, _y1:word, _x2:word,
_y2:word, _color:word 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_x>delta_y && delta_x!=0 ;основное направление - по оси X fild delt
a_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 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 ax, _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 ax, _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 e
ndp
;пауза ~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
end
----- Удачи!
Ответ отправил: Лысков Игорь Витальевич, Модератор
Ответ отправлен: 31.05.2010, 04:48
Номер ответа: 261770 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 261770
на номер 1151 (Россия) |
Еще номера »
Вопрос № 178758:
Здравствуйте, помогите разобраться с процедурой. Т.е. откомментируйте каждую строчку как можно более простым языком (с какой целью это делаем и что получаем), и по возможности изобразите на рисунках (рисовать можно от руки, сфотограффировать, и выложить) как она работает для какого нибудь набора символов. сам код:
видеорежим vga 320x200x256
;выводим текст ;параметры: ;xxStart - X координата начала вывода текста ;yyStart - Y координата начала вывода текста ;pStr - адрес строки ;TextColor
- цвет PrintText proc xxStart:word, yyStart:word, pStr:word, TextColor:word local GenTable:dword ;прочитаем в es:bp длинный адрес таблицы генератора символов push es bp mov ax, 1130h mov bh, 3 int 10h mov ax, bp pop bp mov word ptr GenTable, ax ;сохраним mov word ptr GenTable+2, es pop es mov ax, 320 ;посчитаем адрес начала вывода mul yyStart ;строка add ax, xxStart ;колонка mov di, ax ;с
мещение в видеобуфере mov si, pStr ;адрес строки PT_loop: push di lodsb ;очередной символ cmp al, 0 ;конец строки je PT_ret push ds si ;нарисуем символ по таблице lds bx, GenTable ;адрес таблицы mov ah, 0 ;байт в слово shl ax, 3 ;на символ 8 байт mov si, ax ;смещение в таблице генератора mov ax, TextColor ;цвет mov cx, 8 ;8 строк PT_line_loop: push cx mov ah, [bx+si] ;маска 8 точек в строке inc si mov cx, 8 ;8 точек в
строке PT_column_loop: shl ah, 1 ;смотрим очередной бит jnc PT_column_next mov es:[di], al ;1 - выводим точку PT_column_next: inc di ;на следующую точку в строке loop PT_column_loop add di, 320-8 ;на начало в следующей строке pop cx ;число строк loop PT_line_loop ;по строкам
pop si ds pop di add di,8 ;начало для следующего символа jmp PT_loop ;на следующий символ
Отвечает Лысков Игорь Витальевич, Модератор :
Здравствуйте, Бойко Иван Александрович. Знакомые буковки... Моя подпрограмма, мне и рассказывать... Сначала надо уяснить, что представляет собой знакогенератор. В системе заложены несколько: 8х8, 8х14, 9х14. Будем рассматривать 8х8 (8 точек в строке х 8 строк) Каждый символ кодируется последовательностью байт. В строке 8 точек, каждая точка кодируется битом: 1 - рисуем, 0 - не рисуем. Т.о. на строку достаточно 1 байта, всего 8 строк,
значит, для символа необходимо 8 байт Например, смотрим буковку A:
Ее рисунок соответствует последовательности байт: 30h,78h, 0cch,0cch, 0fch, 0cch, 0cch, 00h И последний момент: чтобы найти индекс нужной последовательности байт в таблице знакогенератора, надо прсто умножить на 8 код символа. Например: для символа 'A' = 41h смещение будет 41h*8=208h
Адрес самой таблицы получаем по mov ax, 1130h mov bh, 3 int 10h Немного добавил комментариев:
Код:
;видеорежим vga 320x200x256
;выводим текст ;параметры: ;xxStart - X координата начала вывода текста ;yyStart - Y координата начала вывода текста ;pStr - адрес
строки ;TextColor - цвет PrintText proc xxStart:word, yyStart:word, pStr:word, TextColor:word local GenTable:dword ;длинный указатель на тавлицу знакогенератора ;прочитаем в es:bp длинный адрес таблицы генератора символов push es bp ;сохраним, т.к. в них вернется указатель mov ax, 1130h ;запрос таблицы mov bh, 3 ;интересует таблица шрифтом 8х8 int 10h mov ax, bp ;перепишем в ax, потому что bp нужен для адресации GenTable pop bp ;восста
новим bp для адресации GenTable mov word ptr GenTable, ax ;сохраним mov word ptr GenTable+2, es pop es ;наконец, восстановим и es mov ax, 320 ;посчитаем адрес начала вывода mul yyStart ;строка * 320 = адрес начала строки add ax, xxStart ;строка * 320 + колонка = адрес точки mov di, ax ;смещение в видеобуфере mov si, pStr ;адрес строки PT_loop: push di ;сохраним начало вывода символа, чтобы легче потом ; было посчитать позицию для следующего символа lodsb ;очередной
символ cmp al, 0 ;конец строки je PT_ret push ds si ;нарисуем символ по таблице lds bx, GenTable ;адрес таблицы 8х8 mov ah, 0 ;байт в слово, которое используем, ; как индекс в таблице знакогенератора shl ax, 3 ;на символ 8 байт, поэтому умножаем на 8 mov si, ax ;смещение 8 байт, описывающих символ, в таблице генератора mov ax, TextColor ;цвет mov cx, 8 ;8 строк PT_line_loop: ;цикл вывода 8-ми строк push cx
;сохраним счетчик строк mov ah, [bx+si] ;читаем из знакогенератора маску 8 точек в строке ;1-рисуем, 0-не рисуем inc si ;смещаем индекс mov cx, 8 ;8 точек в строке PT_column_loop: ;цикл вывода 8-ми точек в строке shl ah, 1 ;смотрим очередной бит, начиная со старшего jnc PT_column_next ;если 0, то не выводим mov es:[di], al ;1 - выводим точку PT_column_next: inc di ;на следующую точку в строке loop PT_column_loop ;и так 8 раз add di, 320-8 ;переходим на
начало следующей строки ; в строке 320 точек, 8 пройдено... pop cx ;число строк loop PT_line_loop ;по строкам
pop si ds ;восстановим адресацию строки pop di ;востановим адресацию символа на экране add di,8 ;сдвигаем на ширину символа для следующего символа jmp PT_loop ;на следующий символ
PT_ret: pop di ;выбросим из стека сохраненный регистр ret PrintText endp
Что непонятно, спрашивайте в мини-форуме.
Растолкую...
----- Удачи!
Ответ отправил: Лысков Игорь Витальевич, Модератор
Ответ отправлен: 30.05.2010, 21:50
Номер ответа: 261765 Украина, Кировоград Тел.: +380957525051 ICQ # 234137952 Mail.ru-агент: igorlyskov@mail.ru Абонент Skype: igorlyskov
Оценка ответа: 5
Вам помог ответ? Пожалуйста, поблагодарите эксперта за это! Как сказать этому эксперту "спасибо"?
Отправить SMS#thank 261765
на номер 1151 (Россия) |
Еще номера »
Отвечает Alex_S, 8-й класс :
Здравствуйте, Бойко Иван Александрович.
я тестировал программу в эмуляторе DOSBOX сделал видеозапись работы в отладчике графика записалась не совсем корректно, поэтому видео экрана с графическим тектом я удалил но на скриншотах виден результат
* Стоимость одного СМС-сообщения от 7.15 руб. и зависит от оператора сотовой связи.
(полный список тарифов)
** При ошибочном вводе номера ответа или текста #thank услуга считается оказанной, денежные средства не возвращаются.
*** Сумма выплаты эксперту-автору ответа расчитывается из суммы перечислений на портал от биллинговой компании.