logo
Программирование в СИ

1.4. Управление цветом

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

Палитру режима можно представить как таблицу, содержащую столько строк (входов), сколько значений допускается для атрибута пикселя в данном графическом режиме. Строки палитры режима нумеруются от нуля до N_palette-1. В строке с номером k содержится код цвета, которым аппаратура видеоадаптера отображает на экране все пиксели страницы, атрибуты которых равны k. Нулевой вход палитры режима, кроме того, определяет цвет фона экрана.

Все графические режимы можно разделить на три группы:

· монохромные режимы, в которых все пиксели могут быть двух цветов - основного и фонового. Палитру таких режимов изменить невозможно;

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

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

Механизм управления цветом в Borland C включает в себя важный элемент - структуру данных, называемую внутренней палитрой. При работе в графических режимах на всех дисплейных адаптерах, кроме VGA и IBM8514, она содержит коды цветов из таблицы цветов адаптера. Роль внутренней палитры при работе с адаптером VGA несколько иная и будет рассмотрена ниже. Драйвер IMB8514 вообще не пользуется внутренней палитрой, поэтому в дальнейшем все, что будет говориться о работе с внутренней палитрой, не относится к этому драйверу. Не следует путать внутреннюю палитру (обычную переменную структурного типа) графической системы с палитрой режима с законом преобразования значения пикселя в цвет.

Определение внутренней палитры как структуры данных имеет вид:

#define MAXCOLOR 15

struct palettetype

{

unsigned char size;

signed char colors[MAX_COLORS+1];

};

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

Для всех монохромных режимов и режимов с фиксированными палитрами допускается использование во внутренней палитре 16 цветов, которые в точности совпадают со стандартными цветами текстового режима. Каждый цвет палитры кодируется числом от 0 до 15. При инициализации таких графических режимов значение каждого элемента массива colors совпадает с его индексом.

В режимах с динамическим управлением внутренняя палитра содержит 16 цветов, коды которых могут лежать в диапазоне от 0 до 63
(т. е. имеется возможность менять содержание внутренней палитры). Для 16 кодов цветов стандартного набора, устанавливаемых при инициализации этих режимов (как для драйвера EGA, так и VGA), определен перечислимый тип EGA_COLORS, т. е. стандартные коды цветов имеют символические имена:

enum EGA_COLORS

{

EGA_BLACK=0, EGA_BLUE=1, EGA_GREEN=2, EGA_CYAN=3, EGA_RED=4, EGA_MAGENTA=5, EGA_BROWN=20, EGA_LIGHTGRAY=7, EGA_DARKGRAY=56, EGA_LIGHTBLUE=57, EGA_LIGHTGREEN=58, ЕGA_LIGHTCYAN=59, EGA_LIGHTRED=60, EGA_LIGHTMAGENTA=61, EGA_YELLOW=62, EGA_WHITE=63

};

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

int far getpalettesize(void);

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

int far getmaxcolor(void);

Непосредственное изменение внутренней палитры осуществляется с помощью функций setpalette или setallpalette. Первая изменяет содержание только одного входа палитры, а вторая всех сразу. Синтаксис первой функции:

void far setpalette(int num_color_pallete,int num_color);

Аргумент num_color_palette задает номер изменяемого входа внутренней палитры и должен лежать в пределах от нуля до size-1 (size - элемент структуры данных palettetype). Аргумент color задает новое значение кода цвета для этого входа в диапазоне от 0 до 63 (реально используются только шесть младших бит аргумента num_color).

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

void far setallpalette(struct palettetype far *palette);

Аргумент ее является указателем на структуру, содержащую ва-риант желаемой палитры. Все изменения в текущей внутренней палитре, произведенные функциями setpalette и setallpalette немедленно отображаются на экране дисплея.

Цветом фона можно управлять с помощью функции

void far setbkcolor(int num_color_palette);

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

Обратной для функции установки цвета фона является функция

int far getbkcolor(void);

которая возвращает текущее назначение для фонового цвета, т.е. номер того входа внутренней палитры, с которым связан в настоящий момент нулевой вход. Если ранее при помощи функции setbkcolor не произошло связывания ни с каким входом, то getbkcolor возвращает 0.

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

void far getpalette(struct palettetype far *palette);

struct palettetype far *getdefaultpalette(void);

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

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

void far setrgbpalette(int num_color,int red,int green,int blue);

Аргумент num_color - номер входа расширенной палитры (0-255), по которому хранятся три цветовые компоненты - красная, зеленая и синяя - составляющие желаемый цвет. Функция позволяет записать по входу расширенной палитры с номером color цветовые компоненты red, green и blue. При этом реально используются только младшие шесть байт каждой компоненты. Таким образом, общее количество цветовых оттенков равно N_colors=64*64*64=256К.

Отметим некоторые особенности использования драйвера VGA. Значения элементов массива colors (кодов цветов) обычной внутренней палитры служат индексами для поиска нужного цвета в расширенной таблице, откуда происходит выбор нужного оттенка цвета.

Заметим, что функция setrgbpalette правильно работает только с дисплейными адаптерами VGA и IBM8514. На других конфигурациях ПК она игнорируется. Кстати, изменить палитру при работе с адаптером IBM8514 можно только при помощи функции setrgbpalette.

Рассмотрим теперь понятие текущего значения рисующего цвета (current drawing color). Рисующий цвет - это то значение, которое используется функциями рисования для записи в атрибуты пикселей. Значение рисующего цвета неотрицательно и не должно превышать значения, возвращаемого функцией getmaxcolor.

Существует функция, позволяющая явно изменять текущее значение рисующего цвета:

void far setcolor(int num_color_palette);

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

int far getcolor(void);