TURBO PASCAL

Новости

Программы   

Turbo Pascal 

Игры

Документация   

Странности

FAQ

Ссылки

Форум

Гостевая книга

Рассылка

Благодарности

Об авторе

 

 

Работа с экраном в графических режимах:

что это за режимы, как в них переключаться, зачем пользоваться утилитой BinObj, что и как можно выводить на экран и как это сохранить для благодарных потомков

Графические режимы

 

В отличие от текстовых режимов, в режимах графических первичным элементом является точка или пиксел (pixel - неправильное, но устоявшееся сокращение от picture element - элемент изображения). Соответственно, все изображение на экране делится на некоторое количество строк и столбцов (различное для каждого из графических режимов). Совокупность количества строк и столбцов какого - либо графического режима называется его разрешением. Каждая точка таким образом характеризуется своими координатами <строка, столбец> и цветом. В зависимости от режима на экране может отображаться различное количество цветов - от 2 до 16777216. Количество цветов определяется количеством бит, используемым для описания одной точки. Совокупность разрешения и цветового разрешения графического режима определяет количество видеопамяти, необходимое для его реализации.

Богатство потенциальных возможностей каждого из графических режимов неоспоримо. Однако, структура видеопамяти для каждого из них различна, что делает различными процедуры вывода и чтения точек экрана. Поэтому, чтобы отделить процедуры вывода графических примитивов - точек, линий, кругов, секторов, etc. - сложных самих по себе из-за дискретности экрана от аппаратно - зависимых (режимо - зависимых) операций чаще всего общение программы с с экраном производится с помощью двух взаимосвязанных средств:
драйвера экрана, отвечающего за аппаратно–зависимые операции (в простейшем случае — точка; в современном мире к этим операциям относят все более и более сложные — вплоть до вывода полиномов и вычислений, связанных с перспективой и Z–порядком);
аппаратно–независимых процедур вывода на экран более сложных элементов и групп элементов.

 

Инициализация и закрытие графики

 

Фирмой Borland в свое время был разработан стандарт на реализацию аппаратно–зависимых драйверов графических режимов экрана (набор реализуемых функций, форматы и тому подобные вещи), что позволило реализовать в модуле Graph множество аппаратно–независимых функций типа вывода линии, окружности и тому подобных. К сожалению, в момент разработки этого модуля то ли не было разработанно быстрых алгоритмов (типа алгоритмов Брезенхэма), то ли унифицированное общение с драйверами занимает слишком много времени, то ли просто разработчики поленились, то ли еще что, но линии и окружности прорисовываются чрезвычайно медленно. Тем не менее для простых приложений модуль вполне достаточен, особенно если учесть, что существует около десятка векторных шрифтов (к сожалению латинских), совместимых с ним. Рассмотрим процедуры и функции модуля Graph.

Для инициализации графического режима необходимо использовать следующие процедуры (по крайней мере вторую из них).

procedure DetectGraph(var GraphDriver, GraphMode : integer); возвращает номера присутствующего аппаратно-зависимого драйвера и доступного видеорежима (с максимальным разрешением)

Эта процедура автоматически вызывается InitGraph и особой необходимости в ее вызове практически никогда не возникает.

procedure InitGraph(var GraphDriver: integer; var GraphMode: integer; PathToDriver : String); инициализирует графический режим в зависимости от доступного драйвера и указанного режима.

BGI–драйвер должен быть доступен по указанному пути или находиться в теле программы и быть зарегистрированным.

Чтобы узнать какой из имеющихся в наличии драйверов был подключен можно использовать

function GetDriverName : String; возвращает название используемого BGI–драйвера

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

function GraphResult : integer; возвращает номер возникшей ошибки и сбрасывает ее
function GraphErrorMsg(ErrorCode : integer): String; по номеру ошибки выдает сообщение ей соответствующее

Для получения информации о текущем видеорежиме следует использовать

function GetMaxMode: integer; возвращает номер максимально доступного режима для текущего драйвера
function GetGraphMode : integer; возвращает номер текущего графического режима

Соответственно для установки одного из видеорежимов стоит использовать

procedure SetGraphMode(Mode : integer); переключает дисплей в указанный режим (номер режима не совпадает с BIOS-овским)

Важно, что при использовании BGI-драйверов это единственно корректный способ смены видеорежима. Связано это с тем, что данная процедура кроме непосредственно установки режима меняет значения внутренних переменных модуля Graph.

Для корректного выхода из графических режимов используют

procedure CloseGraph; завершает сеанс работы с BGI-драйвером

Повышение надежности графических программ:

пожалеем пользователя

Cледует отметить, что для корректной инициализации графики процедуре InitGraph необходим доступ к BGI-драйверу. Стандартным (и очень неудобным) способом предоставления такого доступа является копирование в рабочий каталог программы самого .BGI-файла. При этом возникают проблемы с указанием пути к рабочему каталогу программы и тому подобные (1). Другим способом является динамическая подгрузка "вручную". Для этого каким либо образом производится поиск файла с драйвером, выделение достаточного участка динамической памяти, перемещение в него двоичного образа файла и использование следуюшей процедуры

function RegisterBGIdriver(Driver: pointer): integer; устанавливает связь между внутренними переменными модуля Graph и драйвером, загруженным в ОП по адресу Driver

Данный способ несколько более гибкий (он позволяет загружать различные драйверы, искать их на диске, перегружать драйверы), но все же не избавляет от необходимости иметь на диске дополнительный файл с драйвером (а неопытные пользователи просто забывают его скопировать). Поэтому желательно использовать менее гибкий, но более надежный способ предоставления драйвера - включение его непосредственно в исполняемый код программы, для чего пользуются сначала утилитой BinObj, а затем подключить полученный .Obj файл директивой компилятора $L. Директива BinObj в качестве третьего параметра требует имя процедуры, под которым данный драйвер будет доступен программе. После подключения .Obj файла в тексте программы следует объявить процедуру с таким же именем как внешнюю, для чего после имени процедуры следует указать ключевое слово External. Наличие тела такой процедуры не требуется. После всего этого остается передать указатель на внешнюю процедуру функции RegisterBGIDriver в качестве параметра с помощью @ и инициализировать графику.

{$L EgaVga.Obj}
Procedure EgaVga; external;
{. . . }
RegisterBGIDriver(@EgaVga);
{Let's work!}

Абсолютно аналогично можно поступать и со шрифтами, используя при этом

function RegisterBGIfont(Font : pointer) : integer; устанавливает связь между внутренними переменными модуля Graph и загруженным в ОП двоичным образом шрифта

Вывод графических примитивов

 

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

procedure PutPixel(X, Y : integer; Pixel : word); выводит на экран точку цвета Pixel в координатах X, Y
function GetPixel(X, Y : integer) : word; возвращает цвет точки, высвеченной в координатах X, Y
function GetMaxX : integer;
function GetMaxY : integer;
возвращают соответственно максимальные X и Y координаты для текущего режима (то есть координаты правого нижнего угла экрана)
procedure SetLineStyle(LineStyle : word; Pattern : word; Thickness : word); устанавливает тип линии
procedure GetLineSettings(var LineInfo : LineSettingsType); читает текущие установки для вывода линии. За более подробной информацией рекомендуется обратиться к справочной системе
procedure SetWriteMode(WriteMode : integer); устанавливает способ, которым будет выводиться на экран каждая точка - просто записываться или складываться с уже выведенной по And, Or или XOr
procedure MoveTo(X, Y : integer); перемещает текущий указатель (Current Pointer, аналог курсора - место откуда начинают вывод некоторые процедуры) в позицию X, Y
function GetX : integer;
function GetY : integer;
возвращают координаты CP
procedure MoveRel(Dx, Dy): integer; смещает СР на Dx, Dy от текущего положения
procedure Line(x1, y1, x2, y2 : integer); выводит линию с концами в указаннык координатах; тип линии устанавливается отдельно (см. предыдущие функции)
procedure LineTo(X, Y : integer); выводит линию от текущего положения СР до указанных координат
procedure LineRel(Dx, Dy : integer); выводит линию от текущего положения СР до точки, отстоящей от него на Dx, Dy, после чего перемещает CP в конечную точку линии

Как можно заметить для вывода одного и того же графического примитива (прямой линии) модуль Graph предоставляет целых три процедуры, предоставляя программисту большую свободу при выборе метода вывода на экран - это может быть предварительный обсчет координат, "черепашка", вывод в зависимости от текущего изображения и т.п.

Модуль Graph содержит также множество процедур для вывода других примитивов - прямоугольников (Rectangle), в том числе и закрашенных (Bar) и трехмерных (Bar3D); простых и закрашенных многогранников (DrawPoly и FillPoly); различного рода дуг, окружностей, секторов и элипсов (Arc, Circle, Ellipse, Sector и т.д). За более подробной информацией автор отсылает читающего к справочной системе. 

Также возможны установка и чтение таких параметров, как тип и стиль закраски цвет фона и так далее.

Сохранение изображений

 

Естественной потребностью многих графических приложений является сохранение и восстановление информации с постоянных носителей. Не предоставляя никаких возможностей для работы с различными форматами графических файлов (а значит и предоставляя программисту абсолютную свободу) фирма Borland включила в стандартную библиотеку только следующие процедуры

procedure GetImage(x1, y1, x2, y2: integer; var BitMap); копирует область видеопамяти, относящююся к области экрана с координатами x1, y1, x2, y2 в переменную BitMap; ее структура следующая: ширина, высота, резерв, (x2-x1+1) точек первой строки, затем столько же - второй, etc.
procedure PutImage(X, Y : integer; var BitMap; BitBlt : word); выводит на экран битовую область (полученную с помощью GetImage) в координатах X, Y, складывая каждый пиксел с текущим изображением по And, Or или ХОr в зависимости от BitBlt
function ImageSize(x1, y1, x2, y2 : integer): word; возвращает размер переменной, необходимой для хранения битового образа области экрана с координатами x1, y1, x2, y2

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

(1) Обратно Cвязано это с тем, что нет способа заставить пользователя запускать программу только из того каталога, в котором она находится. Несмотря на то, что полное имя (с путем) запущенной программы можно определить с помощью ParamStr(0), это не всегда работает.

На первую страницу

Rambler's Top100 Rambler's Top100
PROext: Top 1000

(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz