Базовые функции доступа к видеопамяти



 

Практически вся работа с графикой сводится к обмену данными между программой и видеобуфером дисплейного адаптера.

Доступ к отдельным пикселям активной страницы осуществляют две функции:

unsigned far getpixel(int x,int y);void far putpixel(int x,int y,int num_color_palette);

Функция getpixel возвращает атрибут (вход во внутреннюю палитру) пикселя с координатами (x, y). А функция putpixel рисует пиксель в точке с координатами (x, y) цветом, чей код содержится по входу во внутреннюю палитру с номером num_color_palette.

Несмотря на то, что функциям getpixel и pupixel координаты пикселя задаются в системе координат графического окна, ничто не мешает указать координаты любого пикселя страницы, лежащего вне окна. При этом getpixel возвращает правильное значение атрибута указанного пикселя. Поведение функции putpixel зависит от режима отсечения, установленного с помощью последнего аргумента при вызове функции setviewport. Результаты работы функций getpixel и pupixel с выходящими за пределы страницы координатами точек непредсказуемы.

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

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

unsigned far imagesize(int left,int top,int right,int bottom);

Она получает в качестве аргументов координаты левого верхнего и правого нижнего угла сохраняемой области. Возвращаемое значение можно передавать одной из функций выделения памяти для резервирования необходимого пространства. Если объем памяти, требуемый для сохранения изображения, превосходит 64К-1, то функция все равно возвращает значение 0xFFFF, но при этом graphresult выдает значение -11.

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

void far getimage(int left,int top,int right,int bottom,void far *bitmap);

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

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

void far putimage(int left, int top, void far *bitmap, int op);

При этом можно не только указать новое местоположение массива пикселей (через координаты левого верхнего угла), но и вывести его на другую страницу видеопамяти, предварительно сделав ее активной при помощи функции setactivepage. Последний аргумент функции putimage указывает способ, которым атрибуты пикселей массива, выводимого из оперативной памяти на активную страницу, будут замещать уже находящиеся в видеобуфере значения. В простейшем случае, когда op = 0, происходит простое копирование атрибутов пикселей из памяти в видеопамять. Однако возможно выполнение одной из побитовых логических операций над содержимым оперативной памяти и видеобуфера для каждого пикселя массива. Полный набор таких операций задается перечислимым типом putimage_ops:

enum putimage_ops {COPY_PUT, XOR_PUT, OR_PUT, AND_PUT, NOT_PUT};

При работе с функциями getimage и putimage действуют примерно те же правила относительно задаваемых координат, что и для функций getpixel и putpixel: хотя координаты задаются в системе графического окна, можно указать массив пикселей, расположенный в любом месте в пределах активной страницы. Различие между двумя функциями состоит в том, что getimage “схватит” этот массив, а функция putimage выведет массив на страницу так, как если бы никакого графического окна не существовало (т. е. игнорируется режим отсечения).

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

 

Графические примитивы

 

Основное значение графических примитивов – обеспечить наличие программных средств для рисования всевозможных геометрических объектов. Условно можно разбить все графические примитивы по типу рисуемых ими графических объектов на две группы: контурные и площадные. Функции первой группы рисуют всевозможные контурные линии. Ко второй группе относятся функции, предназначенные для рисования геометрических фигур с закрашиванием ограничиваемых ими областей.

К группе контурных графических примитивов относятся функции:

void far line(int x1,int y1,int x2,int y2);void far linerel(int dx,int dy);void far lineto(int x,int y);void far rectangle(int left,int top,int right,intbottom);void far drawpoly(int num_points,int far *poly_points);void far circle(int x,int y,int radius);void far arc(int x,int y,int start_angle,int end_angle,int radius);void far ellipse(int x,int y, int start_angle,int end_angle,int x_radius,int y_radius);

Первые пять рисуют кусочно-линейные объекты (в том числе и фигуры, составленные из отрезков прямых), остальные – кривые второго порядка (дуги окружностей и эллипсов).

Функции line, linerel и lineto соединяют две точки плоскости отрезком прямой. Для первой обе соединяемые точки указываются явно своими координатами. Функции linerel и lineto в качестве первой точки используют текущую графическую позицию CP, а вторую выбирают аналогично функциям moverel и moveto, т. е. через приращения координат или по явному указанию. Все три функции пользуются системой координат графического окна. Однако им можно передать координаты любых точек, даже лежащих за пределами страницы. Функция graphresult не сообщает об ошибке, а соединяющая линия проводится правильно. Если для окна установлен режим отсечения, то части линии, выходящие за пределы окна, не заносятся в видеопамять.

Функция rectangle рисует на странице видеопамяти контур прямоугольника по указанным координатам левого верхнего и правого нижнего угла.

Функция drawpoly рисует ломаную линию, соединяя точки на плоскости. В первом аргументе передается количество таких точек, а второй указывает на массив целых чисел. Каждая пара чисел из этого массива интерпретируется как пара координат (x, y) очередной точки. Для того чтобы нарисовать замкнутую ломаную линию (многоугольник), первая и последняя пары элементов массива должны быть одинаковыми.

Функция circle рисует окружность радиусом radius с центром в точке с координатами (x, y). Функция arc и ellipse вычерчивают дуги окружности и эллипса с центром в точке (x, y), соответственно ограниченные углами start_angle и end_engle. Для дуги окружности задается ее радиус radius, а для дуги эллипса радиусы по осям x_radius и y_radius. Оси эллипса всегда предполагаются параллельными осям координат страницы.

Углы, ограничивающие дуги, выражаются в градусах и отмеряются против часовой стрелки от направления, задаваемого осью X страницы. Дуга всегда проводится от угла start_angle к углу end_angle также против часовой стрелки.

Для функций rectangle, drawpoly, circle, arc и ellipse справедливы замечания относительно системы координат и режима отсечения, которые были сделаны относительно функций рисования линий.

С дугами окружностей связана функция

void far getarccoords(struct arccoordstype far *arccoords);

Эта функция возвращает характеристики дуги окружности, построенной при последнем вызове функции arc. Характеристики дуги записываются в переменную *arccoords. Тип этой переменной определен следующим способом:

struct arccoordstype{int x, y;int x_start, y_start, x_end, y_end;};

Первая пара чисел – это координаты центра окружности, вторая и третья – координаты начала и конца дуги. Значения координат привязаны к системе координат графического окна.

Существуют функции, которые позволяют варьировать внешний вид объектов, например толщину и тип линии, цвет и другие.

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

Для кусочно-линейных графических примитивов, и только для них, имеется возможность указать способ, которым код рисующего цвета будет взаимодействовать с атрибутами пикселей, уже находящимися в видеопамяти на месте рисуемого объекта. Здесь действует механизм, описанный для функции putimage. Выбор способа осуществляется функцией

void far setwritemode(int mode);

Аргумент этой функции должен принимать значение 0 (простое копирование кода атрибута пикселя в видеопамять) и 1 (операция “исключающее или”).

Функция

void far setlinestyle(int line_style,unsigned user_pattern,int thickness);

устанавливает характер и толщину линий геометрических объектов. Аргумент thickness воздействует на контурные графические примитивы, а аргументы line_style и user_pattern – только на кусочно-линейные.

Аргумент thickness принимает значения NORM_WIDTH (толщина равна 1 пиксель) и THICK_WIDTH (толщина равна 3 пикселям). Аргумент linestyle задает характер рисуемой линии. Значения аргумента должны выбираться из констант перечислимого типа line_styles (например SOLID_LINE означает сплошную линию):

enum line_styles{SOLID_LINE=0,DOTTED_LINE,CENTER_LINE,DASHED_LINE,USERBIT_LINE};

Если значение аргумента line_style равно USERBIT_LINE, то это значит, что при построении кусочно-линейных примитивов будет использоваться шаблон, заданный программистом и переданный функции setlinestyle при помощи аргумента user_pattern. С помощью шаблона можно задать периодически повторяющийся рисунок линии с периодом до 16 пикселей. Если некоторый бит шаблона user_pattern равен 1, то соответствующий пиксель линии рисуется, в противном случае – нет.

Установки, сделанные при помощи функции setlinestyle, сохраняются до нового ее вызова. Для выяснения текущей установки характеристик линий предусмотрена функция

void far getlinesettingstype(struct linesettingstype far *line_info);

Данная функция заносит информацию в структуру, имеющую описание

struct linesettingstype{int linestyle;unsigned upattern;int thickness;}

Группа площадных графических функций имеет прототипы:

void far bar(int left, int top, int right, int bottom);void far bar3d(int left, int top, int right, int bottom, int depth, int top_flag);void far fillpoly(int num_points, int far *poly_points);void far fillellipse(int x, int y, int x_radius, int y_radius);void far pieslice(int x, int y, int start_angle, int end_angle, int radius);void far sector(int x, int y, int start_angle, int end_angle, int x_ radius, int y_radius);void far floodfill(int x, int y, int num_color_palette);

Функции bar и bar3d строят прямоугольники, координаты которых заданы первыми четырьмя аргументами функций и закрашивают его внутреннюю область. Функция bar не выводит внешний контур прямоугольника, а функция bar3d дополнительно обрамляет прямоугольник контура и тем же контуром дорисовывает проекцию параллелепипеда, построенного на базе этого прямоугольника. Глубина проекции задается аргументом depth, аргумент top_flag указывает, рисовать (если не нуль) или не рисовать (если нуль) верхние ребра параллелепипеда.

Функция fillpoly получает аргументы аналогично функции drawpoly, рисует контур и заполняет его внутренность. Однако если функция drawpoly допускает незамкнутые контуры, то функция fillpoly всегда соединяет последнюю точку в полученном списке с первой, автоматически замыкая контур.

Функция fillellipse заполняет эллипс с центром в точке (x, y) и радиусами x_radius и y_radius. Кроме того, она рисует контур эллипса.

Функции pieslice и sector похожи тем, что обе закрашивают указанные сектора, только pieslice делает это для кругового сектора, а sector для эллиптического. Аргументы, которые им передаются, те же, что и для функций arc и ellipse соответственно. После того как сектор закрашен, рисуется его контур. В отличие от функций arc и ellipse, функции pieslice и sector строят сектор от меньшего значения угла к большему (а не от start_angle к end_angle). Из-за этого невозможно заставить функции pieslice и sector изобразить сектор, пересекающий положительное направление оси X.

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

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

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

void far setfillstyle(int pattern,int num_color_palette);

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

enum fill_pattern{EMPTY_FILL=0,SOLID_FILL,LINE_FILL,LTSLASH_FILL,SLASH_FILL,BKSLASH_FILL,LTBKSLASH_FILL,HATCH_FILL,XHATCH_FILL,INTERLEAVE_FILL,WIDE_DOT_FILL,    CLOSE_DOT_FILL,USER_FILL};

Аргумент pattern может принимать любые значения, кроме USER_FILL. Значение этой константы используется только при обработке информации, получаемой функцией getfillsettings (см. далее).

Шаблон условно можно представить в виде матрицы размером 8 х 8 элементов. Элементы матрицы шаблона имеют значения 0 или 1. Если элемент равен 1, то атрибуту соответствующего пикселя области будет присвоено значение num_color_palette, в противном случае атрибут пикселя получит значение кода фона.

Возможно создание дополнительных шаблонов непосредственно в прикладной программе. Для этого следует воспользоваться функцией

void far setfillpattern(char far *user_pattern,int num_color_palette);

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

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

void far getfillsettings(struct fillsettingstype far *fill_info);void far getfillpattern(char far *user_pattern);

Первая возвращает в область памяти по указателю fill_info информацию о текущем заполнении. Информация заносится в структуру следующего типа:

struct fillsettingstype{int pattern;int color;};

Элемент структуры pattern указывает тип шаблона (если он равен USER_FILL, то это значит, что шаблон задан пользователем), элемент color содержит код заполнения (номер входа во внутреннюю палитру). Вторая функция по переданному ей адресу записывает матрицу шаблона, установленную пользователем.

 

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

 

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

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

В Borland C предусмотрена работа в графическом режиме с двумя принципиально различными типами графических шрифтов: матричными (bit-mapped) и векторными (stroked). Первый тип представляется только одним шрифтом, изначально встроенным в BIOS компьютера. Шрифтов второго типа может быть несколько.

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

Другой принципиально отличный тип графических шрифтов подразумевает рисование символов тонкими линиями. Поэтому шрифты данного типа можно назвать векторными. Каждый символ представлен последовательностью управляющих кодов, которые заставляют генератор рисовать отрезки прямых линий, соединяющих характеристические точки символа. Таблицы символов векторных шрифтов поставляются в закодированном виде в специальных файлах шрифтов, имеющих расширение .chr. Далеко не все векторные шрифты имеют полный набор 256-ти кодов. Общими для всех шрифтов являются символы с кодами от 32 до 126. Разные символы одного и того же шрифта могут иметь разные размеры в зависимости от ширины конкретного символа.

Существует перечислимый тип font_names, задающий символические имена для номеров пяти графических шрифтов (один матричный и четыре векторных из минимального набора):

enum font_names{DEFAULT_FONT=0, TRIPLEX_FONT, SMALL_FONT, SANS_SERIF_FONT, GOTHIC_FONT};

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

void far settextstyle(int font,int directon,int charsize);

Функция устанавливает основные параметры вывода графических текстов (шрифт, направление строк и размер символа). Эти параметры остаются неизменными до следующего вызова функции settextstyle.

Первый параметр font задает номер инициализируемого шрифта. Ему можно присвоить значение одной из констант перечислимого типа font_names. Набор символов матричного шрифта встроен в BIOS, и от функции не требуется дополнительных действий при его загрузке. Для векторных шрифтов при автоматической загрузке производится поиск соответствующего chr-файла. Сначала просматривается директория, указанная аргументом path_to_bgi функции initgraph, затем текущая директория. Если файл шрифта не найден, устанавливается отрицательный код ошибки. Найденный chr-файл считывается в автоматически выделяемую область памяти. При невозможности выделить необходимую память также устанавливается соответствующий код ошибки. При возникновении любой ошибочной ситуации функция settextstyle выполняется до конца, но инициализирует при этом встроенный матричный шрифт вместо заданного векторного шрифта.

Аргумент direction может принимать одно из значений, определенное константами HORIZ_DIR и VERT_DIR. Он задает направление выводимой строки текста: HORIZ_DIR определяет обычное направление (горизонтальная строка, символы идут слева направо), VERT_DIR разворачивает строку на 90 градусов против часовой стрелки. Использование вертикального расположения строки может привести к изменению пропорций выводимых символов – они становятся ниже и шире, чем в горизонтальной строке, что связано с эффектом “неквадратности” пикселя в некоторых дисплеях и никак неустранимо.

Последний аргумент charsize управляет масштабом выводимых символов. Диапазон допустимых значений: от 1 до 10 для всех графических шрифтов и дополнительное значение 0 только для векторных. Положительное значение charsize указывает на одинаковое увеличение символов по обеим осям. Если для векторных шрифтов задать charsize, равный USER_CHAR_SIZE (определена как 0), то при этом определяются два независимых коэффициента масштабирования – для ширины и высоты символа. По умолчанию в этом режиме знакогенератор рисует символы векторного шрифта в базовом варианте в соответствии с описанием из chr-файла. Однако есть возможность изменить масштаб с помощью функции

void far setusercharsize(int mult_x,int div_x,int mult_y,int div_y);

Данная функция устанавливает новые размеры символа, умножая ширину и высоту базового варианта каждого символа на значения выражения ((double)mult_x / div_x) и ((double)mult_y / div_y) соответственно.

Главным недостатком автоматической инициализации знакогенератора при помощи функции settextstyle является то, что она обращается к диску для чтения chr-файла во время выполнения программы. Альтернативой автоматической инициализации знакогенератора является статическое включение в программу таблицы символов векторных шрифтов. Для этого сначала нужно при помощи утилиты bgiobj.exe превратить chr-файлы в объектные файлы c расширением .obj. Затем их можно включить в программу как обычные объектные файлы.

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

int registerbgifont(void (*font)(void));

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

void triplex_font(void);void small_font(void);void sansserif_font(void);void gothic_font(void);

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

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

void far settextjustify(int horiz,int vert);

Ее аргументы могут принимать значения констант перечислимого типа text_just:

enum text_just{LEFT_TEXT=0, CENTER_TEXT, RIGHT_TEXT,BOTTOM_TEXT, TOP_TEXT};

В случае ошибки функция settextjustify устанавливает код ошибки, равный -11, и сохраняет предыдущий режим позиционирования.

Позиционирование горизонтальных строк происходит следующим образом. Если представить прямоугольник, в который вписана выводимая строка, то пара аргументов horiz и vert описывают положение опорной точки в прямоугольнике.

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

В позиционировании вертикальных строк имеются некоторые особенности. Нужно помнить, что функция settextjustify управляет размещением относительно опорной точки именно прямоугольника, содержащего текст. Из этого следует, что по отношению к самому тексту (поскольку он повернут на 90 градусов) позиционирование справа и слева от опорной точки определяется аргументом vert, а сверху или снизу – аргументом horiz. Аргумент vert обрабатывается так же, как и для горизонтальной строки. Аргумент horiz ведет себя по-другому. При значениях LEFT_TEXT и RIGHT_TEXT он дает одинаковый результат – текстовый прямоугольник располагается слева от опорной точки.

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

void far gettextsettings(struct textsettingstype far *texttypeinfo);

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

struct textsettingstype{int font,direction,charsize;int horiz,vert;};

Для правильного размещения текста на странице необходимо знать размеры занимаемого им пространства, которое зависит от типа шрифта и его масштабирования. Эту информацию выдают функции:

int far textheight(char far *text_string); int far textwidth(char far *text_string);

Они возвращают высоту и ширину (в пикселях) прямоугольника, в который был бы вписан текст при выводе строки text_string знакогенератором текущего шрифта с учетом установленного в данный момент масштаба шрифта. Сам вывод текста при этом не производится.

При своей работе функции вывода текста создают в видеопамяти рисунок символов строки, используя таблицу выбранного шрифта. Код, который при этом заносится в атрибуты пикселей, есть текущее значение рисующего цвета (номер входа во внутреннюю палитру), устанавливаемое функцией setcolor. Никаких битовых операций с атрибутами пикселей видеопамяти не предусмотрено. Линии, которыми рисуются символы векторных шрифтов, всегда сплошные тонкие, они не могут модифицироваться функцией setlinestyle.

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

Функций вывода текста две:

void far outtext(char far *text_string);void far outtextxy(int x,int y,char far *text_string);

Обе в качестве аргумента получают указатель на выводимую строку символов. Отличие между этими функциями состоит в выборе опорной точки при позиционировании сообщения на странице. Функция outtext использует для этого текущую графическую позицию. Функция outtextxy получает координаты опорной точки через аргументы x и y. Координаты задаются в системе координат текущего графического окна. При установке режима отсечения изображения за пределами окна обе функции также обеспечивают отсечение фрагментов текста, выходящего за пределы графического окна.


Дата добавления: 2019-07-17; просмотров: 166; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!