15. Основные графические функции

Глава знакомит читателей с основными функциями стандартной графической библиотеки трансляторов Microsoft Quick C 2.5 и C 6.0. Функции, описанные в этой главе, предоставляют программисту разнообразные возможности управления графическим экраном дисплея.

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

Каждая группа функций сопровождается примерами программ.

15.1. Функция _setpixel()

Функция устанавливает цвет пиксела в заданной позиции экрана. Приведем прототип этой функции:

short _setpixel( short x, short y );

Цвет пиксела устанавливается предварительно функцией _setcolor(). Координаты пиксела задаются параметрами x и y.

Функция возвращает предыдущий цвет пиксела или -1, если произошла ошибка.

15.2. Функция _lineto()

Функция рисует на экране линию. Ее прототип приведен ниже:

short _lineto( short x_target, short y_target );

Линия начинается в текущей точке и заканчивается в точке, имеющей координаты (x_target, y_target). После отображения линии координаты текущей точки становяться равными (x_target, y_target). Для изменения координат текущей точки можно воспользоваться функцией _lineto().

Линия изображается в текущем цвете (функция _setcolor()) и текущем стиле (функция _setstyle()).

Как и все уже рассмотренные функции, функция _lineto() возвращает ненулевую величину, если она выполнилась успешно и ноль, если произошла ошибка.

15.3. Функция _moveto()

Функция изменяет положение текущей точки. Используется совместно с _lineto() для изображения линий. Прототип функции _moveto() имеет следующий вид:

struct xycoord _moveto( short x, short y );

Новые координаты текущей точки соответствуют параметрам функции (точка с координатами (x,y)).

Функция возвращает в структуре xycoord координаты предыдущей точки. Структура xycoord определена в файле graph.h следующим образом:

struct xycoord {

   short xcoord ;      // x координата точки
   short ycoord ;   // y координата точки
};

15.4. Функция _rectangle()

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

short _rectangle( short fill, short x_left,  short y_top,
                              short x_right, short y_bottom );

Прямоугольник определяетя координатами любых двух противоположных углов (x_left,y_top) и (x_right,y_bottom).

Граница прямоугольника изображается текущим цветом с использованием текущего стиля. Если например fill равен _GFILLINTERIOR, то прямоугольник закрашивается, а если _GBORDER - то не закрашивается. Для изменения текущего цвета используют функцию _setcolor().

Функция возвращает ненулевую величину, если она выполнилась успешно и ноль, если произошла ошибка.

Следующая программа иллюстрирует использование функций _moveto(), _lineto() и __rectangle():

#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <graph.h>

// макроопределение, ранжирующее величину, возвращаемую
// генератором случайных чисел (rand) в интервале от  0
// до max

#define random(max) (rand() % (int)((max)+1))


void main(void) {

   short  x, y;
   short  color;
   struct videoconfig vc;

   // устанавливаем графический режим с максимальным числом цветов

   if(!_setvideomode(_MAXCOLORMODE)) {
      puts("Видеоадаптер не поддерживает графический режим.");
      exit(1);
   }

   // получаем информацию о конфигурации видеосистемы и об
   // установленном режиме работы видеоадаптера

   _getvideoconfig(&vc);

   while(!kbhit()) {

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

      _setcolor((short)random(vc.numcolors));

      // выбираем произвольную точку экрана - (x,y)
      x = (short)random(vc.numxpixels),
      y = (short)random(vc.numypixels);

      // рисуем закрашенный и незакрашенный прямоугольники

      _rectangle(_GFILLINTERIOR, x + 30, y + 40, x, y);
      _rectangle(_GBORDER,       x + 40, y + 30, x, y);
   }

   // ожидаем нажатие на клавиатуру

   getch();

   // помещаем текущую точку в центр экрана

   _moveto(vc.numxpixels/2, vc.numypixels/2);

   while(!kbhit()) {
      _setcolor((short)random(vc.numcolors));
      x = (short)random(vc.numxpixels),
      y = (short)random(vc.numypixels);

   // рисуем линию из центра экрана в произвольную точку экрана
      _lineto(x, y);
      _moveto(vc.numxpixels/2, vc.numypixels/2);
   }
   getch();

   // устанавливаем режим видеоадаптера, принятый по умолчанию

   _setvideomode(_DEFAULTMODE);
}

15.5. Функция _ellipse()

Функция рисует эллипс. Приведем прототип этой функции:

short _ellipse( short fill, short x_left,  short y_top,
                            short x_right, short y_bottom );

Эллипс задается прямоугольником, в который он вписан. Прямоугольник определяется координатами любых двух противоположных углов (x_left,y_top) и (x_right,y_bottom). Работа функции иллюстрируется на рисунке 16.1.

    ELLIPSE.PCX;6";2.559";PCX

Рисунок 16.1 Построение эллипса функцией _ellipse().

Граница эллипса изображается текущим цветом. Если аргумент fill функции равен _GFILLINTERIOR, то эллипс закрашивается, а если _GBORDER - то не закрашивается. Для изменения текущего цвета используют функцию _setcolor().

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

Функция возвращает не нулевую величину, если она выполнилась успешно и ноль, если произошла ошибка.

15.6. Функция _arc()

Функция рисует дугу эллипса.

Прототип функции _arc() имеет следующий вид:

short _arc( short x_left,  short y_top,   short x_right, short y_bottom,
            short x_begin, short y_begin, short x_end,   short y_end );

Эллипс задается прямоугольником, в который он вписан. Прямоугольник определяетя координатами любых двух противоположных углов (x_left, y_top) и (x_right, y_bottom). Дуга строится от точки пересечения эллипса с прямой, соединяющей центр эллипса с точкой (x_begin, y_begin) до точки пересечения эллипса прямой, соединяющей его центр с точкой (x_end, y_end) против часовой стрелки (см. рисунок 16.2).

    ARC.PCX;6";3.439";PCX

Рисунок 16.2 Построение дуги эллипса функцией _arc().

Функция возвращает ненулевую величину, если она выполнилась успешно и ноль, если произошла ошибка.

15.7. Функция _pie()

Функция рисует сектор эллипса:

short _pie( short fill,
   short x_left,  short y_top,   short x_right, short y_bottom,
   short x_begin, short y_begin, short x_end,   short y_end );

Эллипс задается прямоугольником, в который он вписан. Прямоугольник определяетя координатами любых двух противополжных углов (x_left, y_top) и (x_right, y_bottom). Дуга сектора строится от точки пересечения эллипса с прямой, соединяющей центр эллипса с точкой (x_begin, y_begin) до точки пересечения эллипса прямой, соединяющей его центр с точкой (x_end, y_end) против часовой стрелки (см. рисунок 16.3).

    PIE.PCX;6";3.439";PCX

Рисунок 16.3   Построение сектора эллипса при помоши функции _pie().

Граница эллипса изображается текущим цветом. Если поле fill равно _GFILLINTERIOR, то эллипс закрашивается, а если _GBORDER - то не закрашивается. Для изменения текущего цвета используют функцию _setcolor().

Функция возвращает ненулевую величину, если она выполнилась успешно и ноль, если произошла ошибка.

15.8. Функция _setcolor()

В графическом режиме видеоадаптера функция _setcolor() устанавливает текущий цвет, используемый функциями _setpixel(), _lineto(), _rectangle(), _ellipse(), _arc(), _pie().

Прототип функции _setcolor() приведен ниже:

short _setcolor( short color );

Параметр color должен содержать индекс цвета. По умолчанию используется цвет с наибольшим индексом в палитре цветов.

Функция возвращает предыдущий индекс цвета. В случае ошибки функция возвращает -1.

15.9. Функция _selectpalette()

Функция изменяет цветовую палитру для режимов _MRES4COLOR и _MRESNOCOLOR. В этих режимах цветовая палитра содержит четыре цвета - цвет фона, выбираемый отдельно и три цвета, устанавливаемых функцией _selectpalette(). Функция имеет следующий прототип:

short _selectpalette( short palette_number );

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

В режиме _MRES4COLOR параметр palette_number выбирает одну из четырех возможных цветовых палитр:

Номер палитры       Индекс 1    Индекс 2    Индекс 3
(palette_number)

0                   зеленый     красный     коричневый
1                   синий       малиновый   светло-
                                            серый
2                   светло-     светло-     желтый
                    зеленый     красный
3                   светло-     светло-     белый
                    синий       малиновый

В режиме _MRESNOCOLOR, для видеоадаптера CGA с цветным дисплеем используется следующая цветовая палитра:

Номер палитры       Индекс 1    Индекс 2    Индекс 3
(palette_number)

0                   голубой     красный     светло-
                                            серый
1                   светло-     светло-     белый
                    голубой     красный

Если вместо адаптера CGA подключен EGA, то доступны три цветовых палитры:

Номер палитры       Индекс 1    Индекс 2    Индекс 3
(palette_number)

0                   зеленый     красный     коричневый
2                   светло-     светло-     желтый
                    зеленый     красный
3                   светло-     светло-     желтый
                    синий       красный

Функция _selectpalette() возвращает номер предыдущей используемой цветовой палитры.

15.10. Функция _setlinestyle()

Функция определяет маску, используемую при рисовании линий функцией _lineto():

void _setlinestyle( unsigned short mask );

Единственный параметр функции является набором из 16 бит. Каждый бит соответствует пикселу на отображаемой линии. При этом если бит параметра равен единице, то соответствующий ему пиксел на линии отображается текущим цветом. А если бит параметра равен нулю, то пиксел не отбражается.

Если функция _setlinestyle() не вызывалась, то по умолчанию маска равна 0xFFFF, и, следовательно, все пикселы линии отображаются на экране.

15.11. Функция _setviewport()

Мы будем использовать две различные системы координат - физическую и логическую.

Начало физической системы координат находится в левом верхнем углу экрана дисплея. Оси координат x и y направлены соответственно слева направо и сверху вниз.

Логическая система координат представляет собой прямоугольную область. Ее начало координат расположено в левом верхнем углу прямоугольной области, а оси координат направлены следующим образом: одна - вправо, другая - вниз. По умолчанию, логическая система координат совпадает с физической. Для ее изменения предназначены функции _setviewport() и _setvieworg(). Подавляющее большинство основных графических функций стандартной библиотеки трансляторов Microsoft Quick C 2.5 и C 6.0 применяют логическую систему координат.

Прототип функции _setviewport() приведен ниже:

void _setviewport( short x_first,  short y_first,
             short x_second, short y_second );

Параметры функции x_first, y_first и x_second, y_second задают прямоугольную область экрана, в которую направляется последующий вывод графической информации. При этом верхний левый угол области является началом координат созданной логической системы координат.

15.12. Функция _setvieworg()

Функция перемещает начало логических координат (точку (0, 0)) в точку экрана, имеющую физические координаты (x, y). Прототип функции имеет следующий вид:

struct xycoord _setvieworg( short x, short y );

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

15.13. Функция _setvideomoderows()

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

Функция имеет следующий прототип:

short _setvideomoderows( short mode, short rows );

Первый параметр функции - mode, определяет режим, в который переводится видеоадаптер. Этот параметр может быть равен одной из следующих констант:
_DEFAULTMODE, _ERESCOLOR, _ERESNOCOLOR, _HERCMONO, _HRES16COLOR, _HRESBW, _MAXCOLORMODE, _MAXRESMODE, _MRES4COLOR, _MRES16COLOR, _MRES256COLOR, _MRESNOCOLOR, _ORESCOLOR, _TEXTBW40, _TEXTBW80, _TEXTC40, _TEXTC80, _TEXTMONO, _VRES2COLOR, _VRES16COLOR.
Эти константы описаны в таблице 16.1:

Константа      Режим     Характеристики

_TEXTBW40      0, 1      текстовый, 40x25, 16 градаций
                         серого цвета
_TEXTC40       0, 1      текстовый, 40x25, 16 цветов
_TEXTBW80      2, 3      текстовый, 80x25, 16 градаций
                         серого цвета
_TEXTC80       0, 1      текстовый, 80x25, 16 цветов
_MRES4COLOR    4, 5      графический, 320x200, 4 цвета
_MRESNOCOLOR   4, 5      графический, 320x200, 4 
                         градации серого цвета
_HRESBW        6         графический, 640x200, 2
                         градации серого цвета
_TEXTMONO                текстовый, 80x25, монохромный
_HERCMONO      Hercules  графический, 720x348,
                         монохромный
_MRES16COLOR   0Dh       графический, 320x200, 16
                         цветов
_HRES16COLOR   0Eh       графический, 640x200, 16
                         цветов
_ERESNOCOLOR   0Fh       графический, 640x350,
                         монохромный
_ERESCOLOR     10h       графический, 640x350, 16
                         цветов
_VRES2COLOR    11h       графический, 640x480, 2 цвета
_VRES16COLOR   12h       графический, 640x480, 16
                         цветов
_MRES256COLOR  13h       графический, 320x200, 256
                         цветов
_ORESCOLOR     Olivetti  графический, 640x400, 1 из 16
                         видеоадаптер фирмы Olivetti
_DEFAULTMODE             режим, используемый видеоадаптером по 
                         умолчанию
_MAXRESMODE              графический режим с наивысшим
                         разрешением доступным на данном
                         видеоадаптере
_MAXCOLORMODE            графический режим с наибольшим числом
                         цветов поддерживаемых видеоадаптером

Таблица 16.1 Режимы работы видеоадаптеров.

Если устанавливается текстовый режим видеоадаптера, то второй параметр функции (rows), задает число строк на экране дисплея.

Второй параметр может быть равен константе _MAXTEXTROWS. В этом случае устанавливается максимально возможное для данной видеосистемы число строк. У видеоадаптера VGA это 50, EGA - 43, а у других адаптеров - 25 строк в текстовых режимах.

Функция возвращает число строк на экране дисплея или 0, если произошла ошибка (запрашиваемый режим не поддерживается видеоадаптером).

15.14. Функция _getimage()

Функция имеет следующий прототип:

_getimage( short x_first,  short y_first,
       short x_second, short y_second,
       char  _huge *image );

Она записывает содержимое прямоугольной области экрана, определенной точками (x_first, y_first) и (x_second, y_second) в буфер, на который указывает параметр image. Необходимый размер буфера можно узнать при помощи функции _imagesize().

15.15. Функция _putimage()

Функция имеет следующий прототип:

void _putimage( short x, short y, 
          char _huge *image,
          short action );

Функция помещает пиктограмму, записанную в буфере image, на экран. При этом верхняя левая точка пиктограммы помещается в точке с координатами (x, y).

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

Констаната    Смысл

_GAND         записываемая пиктограмма накладывается
              на область экрана так, что результат
              получается как логическое "И" данных
              пиктограммы и экрана
_GOR,         записываемая пиктограмма накладывается
              на область экрана так, что результат
              получается как логическое "ИЛИ" данных
              пиктограммы и экрана
_GXOR         записываемая пиктограмма накладывается
              на область экрана так, что результат
              получается как логическое "ИСКЛЮЧАЮЩЕЕ
              ИЛИ" данных пиктограммы и экрана
_GPRESET      копирует пиктограмму на экран, при этом
              цвет каждого пиксела инвертируется
_GPSET        копирует пиктограмму на экран, при этом
              цвет каждого пиксела сохраняется

Таблица 16.2 Различные способы записи пиктограмм.

15.16. Функция _imagesize()

Функция возвращает размер буфера (в байтах), необходимого для сохранения прямоугольного участка экрана дисплея, задаваемого двумя диагонально противоположными точками - (x_first, y_first) и (x_second, y_second).

long _imagesize( short x_first,  short y_first,
           short x_second, short y_second );

Функция определяет размер буфера по следующим формулам:

width  = abs(x_first-x_second) + 1;
height = abs(y_first-y_second) + 1;
size=((long)((width * bits_per_pixel + 7) / 8)*(long)height) + 4;

Величина bits_per_pixel, содержит число битов видеопамяти определяющих один пиксел. Этот параметр режима видеоадаптера можно получить через функцию _getvidioconfig().

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

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

#include <conio.h>
#include <stdlib.h>
#include <malloc.h>
#include <graph.h>


void main(void)
{
   char  _huge *buffer;
   char  text[8];
   long  imsize;
   short i, x = 0, width = 60, height = 27;

   // выбираем режим видеоадаптера с наибольшим разрешением

   if(!_setvideomode(_MAXRESMODE))
      exit(1);

   sprintf(text, "текстовая строка");

   // отображаем на экране несколько строк text

   for(i = 1; i < 8; i++) {
      _settextposition(i, i);
      _outtext(text);
   }

   // определяем размер буфера для пиктограммы высотой height
   // и шириой width

   imsize = _imagesize(0, 0, width, height);

   // резервируем буфер памяти для пиктограммы

   buffer = halloc(imsize, 1);
   if(buffer == NULL)
      exit(1);

   // запоминаем пиктограмму в буфере

   _getimage(0, 0, width, height, buffer);

   // перемещаем пиктограмму по экрану дисплея

   while(x < 400)

      // отображаем пиктограмму

      _putimage(x++, 0, buffer, _GPSET);

   getch();
   free(buffer);
}