Воспроизведение не сжатых рисунков
Текст подпрограммы, выполняющей построение рисунка произвольного размера, приведен в примере 3.22. Перед ее вызовом в регистре di надо указать адрес левой верхней точки рисунка в видеопамяти и установить окно, которому принадлежит этот адрес. Напоминаем, что регистр es должен содержать код видеосегмента (содержимое переменной vbuff).
Пример 3.22. Построение рисунка произвольного размера.
| SwpOf fs | dw 0 | адрес (смещение) в буфере обмена |
| SwpSeg | dw 0 | значение сегмента, содержащего буфер обмена |
| iwidth | dw 0 | ширина строки рисунка |
| iheight | dw 0 | количество строк в рисунке |
| numbyte | dw 0 | количество байтов в считываемой порции данных |
| part | dw 0 | количество строк в считываемой порции данных |
| remline | dw 0 | остающееся не выведенным количество строк |
| jnc sucread | › чтение без ошибок | |
| i | Здесь должны выполняться действия при ошибке чтения | |
| sucread: | mov ex, part | сх = стандартное количество строк |
| cmp remline, ex | осталось меньше строк? | |
| jae @F | › нет, обходим команду пересылки | |
| mov ex, remline | сх = оставшееся число строк | |
| @@: | sub remline, ex | уменьшаем оставшееся число строк |
| xor si, si | адрес начала в буфере обмена | |
| drwout: | push ex | сохраняем счетчик повторов |
| mov ex, iwidth | задаем размер строки рисунка | |
| call drawline | построение очередной строки | |
| pop ex | восстанавливаем счетчик повторов | |
| add di, bx | адрес начала следующей строки | |
| jnc @F | › адрес в пределах сегмента | |
| call NxtWin | установка следующего окна | |
| @@: | loop drwout | управление повторами цикла |
| cmp remline, 0 | все строки выведены? | |
| jne NewPart | › нет, продолжаем построение | |
| PopReg <Cur win, fs> | восстановление Cur win и fs | |
| popa | восстановление всех регистров | |
| call setwin | восстановление исходного окна | |
| ret | возврат из подпрограммы | |
Выполнение подпрограммы примера 3.22 начинается с подготовительных действий. Две первые команды сохраняют в стеке содержимое используемых регистров и значение переменной Cur_win. Затем в регистр fs помещается сегмент буфера обмена, а переменная Swpoffs очищается для расположения считываемых из файла данных с начала буфера обмена. Следующие восемь команд формируют значение переменных part, numbyte, и remline, последняя является счетчиком еще не выведенных строк, поэтому ее исходное содержимое равно высоте рисунка. Остается сформировать в регистре bx константу horsize – iwidth для коррекции адресов строк в видеопамяти.
Построение рисунка выполняют два вложенных цикла. Внешний имеет метку NewPart, а внутренний – drwout. Во внешнем цикле производится чтение из файла очередной порции данных, уточнение размера прочитанной порции (содержимого регистра сх), оставшегося количества строк (переменная remline) и очистка регистра si. После этого выполняется внутренний цикл, выводящий на экран прочитанную порцию строк.
Внутренний цикл полностью совпадает с аналогичным циклом примера 3.21, поэтому мы опустим его описание.
По окончании работы внутреннего цикла проверяется значение переменной remline и если оно отлично от нуля, то происходит возврат на начало внешнего цикла. Если все строки выведены на экран, то восстанавливаются сохраненные в стеке величины, исходное окно видеопамяти и происходит возврат на вызывающий модуль.
