Найти в Дзене
Самоучка

А как вывести на экран что то более чем прямоугольник?

В познавательных целях выводить прямоугольник в цвете на экран, это конечно замечательно. Но пора двигаться дальше и отобразить какую нибудь загруженную картинку. А если ещё и на полный экран... Но вот досада. Полноэкранное изображение занимает 81 920 байт памяти, в то время как из доступной у нас всего ничего, 65 536 байт и то часть уже занята под DOS и даже моим кодом... В общем, в данной статье постараюсь объединить усвоенные ранее знания. Что в итоге требуется? Выделить необходимый объем памяти, загрузить в него файл, вывести содержимое файла на экран. Ну и собственно само изображение тоже понадобится. Изображение я решил скачать из интернета. Само изображение у нас будет в формате BMP. Это несжатое изображение имеет очень простое устройство файла. Касательно изображений где палитра состоит из 256 цветов, то навскидку описание файла примерно такое, что идет шапка с параметрами файла, затем идет палитра цветов, после чего идут сами данные в перевёрнутом виде. Ну т.е. картинка рису

В познавательных целях выводить прямоугольник в цвете на экран, это конечно замечательно. Но пора двигаться дальше и отобразить какую нибудь загруженную картинку. А если ещё и на полный экран...

Но вот досада. Полноэкранное изображение занимает 81 920 байт памяти, в то время как из доступной у нас всего ничего, 65 536 байт и то часть уже занята под DOS и даже моим кодом...

В общем, в данной статье постараюсь объединить усвоенные ранее знания.

Что в итоге требуется? Выделить необходимый объем памяти, загрузить в него файл, вывести содержимое файла на экран. Ну и собственно само изображение тоже понадобится.

Изображение я решил скачать из интернета.

Пусть это будут Чип и Дэил
Пусть это будут Чип и Дэил

Само изображение у нас будет в формате BMP. Это несжатое изображение имеет очень простое устройство файла. Касательно изображений где палитра состоит из 256 цветов, то навскидку описание файла примерно такое, что идет шапка с параметрами файла, затем идет палитра цветов, после чего идут сами данные в перевёрнутом виде. Ну т.е. картинка рисуется снизу вверх.

Если же дать более полное описание BMP файла, то вот пример:

Устройство BMP файла
Устройство BMP файла

В общем от этого и будем отталкиваться. Проведя простейшие математические вычисления, приходим к выводу, что памяти мне понадобиться ровно пять страниц по 16384 байт. Следовательно картинку придется загружать частями и выводить соответственно так же. Но здесь как говориться у нас два путя: Первый лёгкий - это прибегнуть к помощи PC и на нем покромсать изображение, а второй несколько сложнее, но который позволит загрузить изображение целиком непосредственно на самом компьютере Спринтер.

К слову, если подготовить изображение правильно и разделить его на пять вертикальных частей где width = 64 бита, а height = 256 бит, то как мне кажется, данная картинка и выводилась бы проще, а соответственно быстрее, поскольку не пришлось бы следить за шириной экрана, а просто последовательно вывести пять частей, каждая со своим смещением.

Но я не стану прибегать к такому читерству, а начну подготавливать себе библиотеку по работе с графикой и постараюсь написать полноценные функции, которые будут загружать BMP файл и выводить его на экран.

Что же, пожалуй хватит разглагольствовать и пора начинать писать код.

Для начала создам еще один файл с набором функций и подключу его в основной код с помощью include. Это будет файл files.h, где я буду описывать библиотеки для работы с файлами. Загрузка, выгрузка, если понадобится. Приму для себя за правило, хотя возможно это и не правильно, но я пока это вижу так, что при загрузке файла, будет создаваться банк памяти, куда этот файл и будет загружаться, а на выходе функции будет id этого файла и количество страниц памяти, которые были запрошены на его загрузку. Оговорюсь, сделаю ещё маленькие функции, которые пишут по текущим адресам, специально для небольших данных.

И вот при написании данного файла, я пришел к выводу, что текущими средствами компьютера Спринтер, сделать это очень сложно. Встроенный в FN текстовый редактор, постоянно доставляет проблемы, в виде того, что начинает дублировать строки, да и просто делает что то непонятное. Последней чашей, переполнившей моё терпение, стал тот факт, что только что нормально компилировавшийся файл, вдруг начал выдавать кучу ошибок. Ошибки, характера, что не может найти часть меток при компиляции. Что удивительно, в файле описаны две подпрограммы использующие обращения к данным меткам. Но вот та, что идёт первая, она сыпет ошибками, а вторая подпрограмма, нормально проходит. Закомментировав строки с ошибками первой подпрограммы, вторая часть успешно компилируется. Я долго пытался решить эту проблему. Осталось, только переписать файл полностью... Но поскольку это самое начало программирования, а уже есть проблемы, то сложно представить, сколько еще раз мне придется переписывать эти файлы сначала. В общем я решил не рисковать и продолжить изучение ассемблера для Z80 в более тепличных условиях, на PC используя компилятор sjasm. К тому же с отладчиком DEMON на реальной машине тоже не задалось. Как только начинаю отлаживать код с вызовом функций DOS или BIOS, компьютер зависает. Возможно я просто не разобрался, но это всё отнимает увы много времени. А хочется всё и сразу.

В общем, перехожу на sjasm.

К сожалению, это означает, что придется начинать практически сначала. Разве что, не стану вновь писать программу Hello world! Остальное же придется набрать повторно.

Исходные файлы буду набирать в Notepad ++.

И так приступаю.

Аналогичным образом создам папку Dzen_prj. И заполню её необходимым содержимым. Создаю для начала папки image, include, tools. В папку include помещаю наши файлы с описанием функций DOS и BIOS, это dss.asm, bios.asm, а так же файлы sp.asm и head.asm. Последний нужен для того, чтобы создать запускной файл DOS, поскольку в отличии от компилятора ассемблера ORGASM, компилятор sjasm не умеет создавать exe файлы, для данной операционной системы.

Теперь создам пустой файл, с подключенными файлами описанными мною ранее.

Так теперь выглядит мой исходный, пустой файл.
Так теперь выглядит мой исходный, пустой файл.

Если быть совсем откровенным, то я и файлы dss.asm с bios.asm тоже решил взять готовые. Файлы file.asm и graphics.asm переписал с нуля, добавив новых функций, но исключив пока отрисовку прямоугольника. Получилось конечно же не без нюансов, но что поделать учусь...

Однако о бо всём по порядку.

file.asm

Здесь я описал такие функции как:

  • LoadFile
  • LoadBigFile
  • LoadBmpFile
  • OpenFile
  • CloseFile

а так же некоторый набор переменных:

  • idfile
  • bankfile
  • pagesbankf

Переменные необходимы для работы всех вышеописанных функций, где хранятся идентификаторы открываемого файла, создаваемого банка памяти и номер страницы памяти, который считается при загрузке больших файлов.

Функции OpenFile и CloseFile, они хоть и могут применяться сами по себе, но всё же больше нужны для работы первых трёх функций. Первая открывает файл и создает его идентификатор, вторая его закрывает используя созданный ранее идентификатор. Этот же идентификатор используется всеми тремя функциями, которые уже непосредственно и загружают файл в память компьютера.

LoadFile - это самая маленькая и самая простая функция, которая загружает файл объемом не более 64кб в память компьютера, но даже так лучше ее не использовать. Поскольку можно попасть в область DOS или же испортить системный стек. Лично я ограничиваюсь загрузкой в одно окно процессора, либо первое либо в третье. Но в текущем примере эту функцию, ровно как и следующую использовать не буду, написал её скорее на будущие нужды. Для вызова данной функции необходимо указать следующие данные:

  • HL - путь к файлу
  • BC - количество загружаемых байт
  • DE - адрес куда грузится файл

LoadBigFile - данная функция в отличии от предыдущей уже способна загружать файлы большего объема, но для этого она выделяет банк памяти и присваивает ему идентификатор. На входе указываем только путь к файлу в регистровой паре HL. На выходе id выделенного банка, переменная bankfile и количество страниц в переменной pagesbankf.

LoadBmpFile - ну и то о чём пошел разговор в начале статьи. Функция которая грузит BMP файлы. На этом этапе стоит сделать оговорку. Что бы в процессе обучения не сломать себе мозг, я ограничился форматом BMP файлов 320*256 точек при 256 цветах. Что понесло за собой следующие ограничения. Выделяется банк памяти на шесть страниц, где нулевая страница, это описатель самого файла и его палитра. Мало ли, понадобится в следующих ревизиях создаваемой мною библиотеки. А оставшиеся пять страниц это сами данные.

Теперь опишу файл graphics.asm

В данном файле я написал немного больше, хотя на данном этапе, большая часть описанного излишня. Но тем не менее.

  • Graphics - Устанавливает видео режим и отображаемую видео страницу
  • SetPalette - Устанавливает палитру (в HL - адрес палитры)
  • ErasePalette - Очищает палитру
  • Copy_Palette - копирует палитру на второй экран
  • UpPalette - Постепенно с 0 поднимает палитру до цветов палитры указанной по адресу в регистровой паре DE
  • DownPalette - постепенно гасит все цвета палитры в ноль
  • clrscr - очищает экран
  • DrawBMP - отрисовывает BMP изображение. Данная функция содержит в себе множество переменных такие как размер изображения его координаты на экране. Что говориться с заделом на будущее. И по факту, что бы вывести данное изображение, эти параметры необходимо указать. Но данная функция пока не умеет расшифорвывать заголовок BMP файла. Пока я не стал с этим заморачиваться, отложив данное действие на потом, когда опыта наберусь побольше.

Весь проект будет в закрепленной ссылке и желающие смогут его собрать.

Ниже привожу скриншот основного Main.asm файла.

Main.asm файл
Main.asm файл

В данном файле вызываю последовательно функции установки видеорежима, загрузки файла, установки палитры и соответственно отрисовки BMP изображения.

В спешке забыл прописать комментарии в файле Main.asm

Результат работы программы на эмуляторе ZXMAK II
Результат работы программы на эмуляторе ZXMAK II

Ссылка на проект: https://disk.yandex.ru/d/dg1TxhOW8e-zwQ