Страница Ивана Рощина > Статьи >

© Иван Рощин, Москва

ZXNet: 500:95/462.53
E-mail: bestview@mtu-net.ru
WWW: http://www.ivr.da.ru

Создание VGA-палитры с плавными переходами цветов

Радиомир. Ваш компьютер» 9/2003)

Введение

При программировании графических эффектов, работающих в 256-цветных режимах видеоадаптера VGA, часто возникает необходимость так переопределить всю палитру или её часть, чтобы получились плавные переходы от одного цвета к другому. Предлагаю использовать для вычисления RGB-компонент переопределяемого участка палитры приведённую ниже программу, написанную на Turbo C.

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

После запуска программа показывает на экране все вычисленные цвета палитры (см. рис. 1, 2), а после нажатия любой клавиши — записывает (если нужно) файл c компонентами этих цветов и завершает свою работу.

Базовые цвета (их можно задать произвольное количество) определяются путём указания их RGB-компонент, каждая из которых может быть в диапазоне 0—63. Значения компонент нескольких «основных» цветов приведены в табл. 1.

Табл. 1
ЦветRGB
чёрный000
синий0063
зелёный0630
голубой06363
красный6300
фиолетовый63063
жёлтый63630
белый636363

Текст программы

/* Программа формирования VGA-палитры
   с плавным переходом между заданными цветами.
   (с) Иван Рощин, Москва, 2002. */

#include <dos.h>
#include <stdio.h>

#define pal_len  256  /* Длина палитры (1-256). */
#define pal_loop 0    /* 0 - незацикленная палитра, 1 - зацикленная. */

/* Базовые цвета (между которыми будет плавный переход): */
int base_colors[]={0,0,0, 63,63,63};

#define save_mode 0  /* 0 - не записывать палитру,
                        1 - записать в двоичный файл,
                        2 - записать в текстовый файл (asm). */

char *save_name="";      /* Имя записываемого файла. */

void main ()
{
 int palette_r [pal_len]; /* Компоненты формируемой палитры. */
 int palette_g [pal_len];
 int palette_b [pal_len];
 int n=sizeof(base_colors)/(sizeof(int)*3); /* Количество базовых цветов. */
 int i,j;
 int base;
 float part;
 union REGS rg;
 unsigned char mode;
 FILE *f_dst;

/* Формируем палитру. */

#if (pal_loop==0)
 /* Палитра не зациклена. */
 /* Для всех элементов палитры, кроме последнего: */
 for (i=0; i<(pal_len-1); i++)
 {
  base=i/(((float)(pal_len-1))/(n-1));
  part=i/(((float)(pal_len-1))/(n-1))-base;
  palette_r[i]=base_colors[base*3]*(1-part)+base_colors[base*3+3]*part+0.5;
  palette_g[i]=base_colors[base*3+1]*(1-part)+base_colors[base*3+4]*part+0.5;
  palette_b[i]=base_colors[base*3+2]*(1-part)+base_colors[base*3+5]*part+0.5;
 }
 /* Цвет последнего элемента палитры
    равен последнему базовому цвету: */
 palette_r[pal_len-1]=base_colors[(n-1)*3];
 palette_g[pal_len-1]=base_colors[(n-1)*3+1];
 palette_b[pal_len-1]=base_colors[(n-1)*3+2];
#else
 /* Палитра зациклена. */
 for (i=0; i<pal_len; i++)
 {
  base=i/(((float)pal_len)/n);
  part=i/(((float)pal_len)/n)-base;
  if (base<(n-1))
  {
   palette_r[i]=base_colors[base*3]*(1-part)+base_colors[base*3+3]*part+0.5;
   palette_g[i]=base_colors[base*3+1]*(1-part)+base_colors[base*3+4]*part+0.5;
   palette_b[i]=base_colors[base*3+2]*(1-part)+base_colors[base*3+5]*part+0.5;
  }
  else /* base=n-1 */
  {
   palette_r[i]=base_colors[(n-1)*3]*(1-part)+base_colors[0]*part+0.5;
   palette_g[i]=base_colors[(n-1)*3+1]*(1-part)+base_colors[1]*part+0.5;
   palette_b[i]=base_colors[(n-1)*3+2]*(1-part)+base_colors[2]*part+0.5;
  }
 }
#endif

/* Определяем и запоминаем текущий режим работы видеоадаптера: */

 rg.h.ah=0x0f;
 int86 (0x10, &rg, &rg);
 mode=rg.h.al;

/* Включаем режим 320*200*256: */

 rg.x.ax=0x0013;
 int86 (0x10, &rg, &rg);

/* Выводим в центре экрана прямоугольник, в котором представлены все цвета
   сформированной палитры. Если сформированная палитра содержит менее 256
   элементов, то первые элементы текущей палитры не будут затронуты; таким
   образом, фон останется чёрным. Иначе фон будет таким, каков цвет первого
   элемента палитры. */

 for (i=0; i<pal_len; i++)
 {
  rg.h.ah=0x10;              /* Устанавливаем новое значение */
  rg.h.al=0x10;              /* элемента палитры.            */
  rg.h.bh=0;
  rg.h.bl=i+(256-pal_len);
  rg.h.dh=palette_r[i];
  rg.h.ch=palette_g[i];
  rg.h.cl=palette_b[i];
  int86 (0x10, &rg, &rg);

  for (j=90; j<110; j++)     /* Изображаем вертикальную линию */
  {                          /* соответствующего цвета. */
   rg.h.ah=0x0c;
   rg.h.al=i+(256-pal_len);
   rg.h.bh=0;
   rg.x.cx=i+((320-pal_len)/2);
   rg.x.dx=j;
   int86 (0x10, &rg, &rg);
  }
 }

/* Ждём нажатия клавиши и восстанавливаем прежний режим
   работы видеоадаптера: */

 while (bioskey(1)==0);
 rg.h.ah=0;
 rg.h.al=mode;
 int86 (0x10, &rg, &rg);

/* Если надо, записываем палитру в файл: */

#if (save_mode==1)
 f_dst=fopen(save_name,"wb");
 for (i=0; i<pal_len; i++)
 {
  fputc(palette_r[i],f_dst);
  fputc(palette_g[i],f_dst);
  fputc(palette_b[i],f_dst);
 }
 fclose(f_dst);
#endif

#if (save_mode==2)
 f_dst=fopen(save_name,"wt");
 for (i=0; i<pal_len; i++)
 {
  fprintf (f_dst,"%s","        db ");
  fprintf (f_dst,"%u%c",palette_r[i],',');
  fprintf (f_dst,"%u%c",palette_g[i],',');
  fprintf (f_dst,"%u%c",palette_b[i],'\n');
 }
 fclose(f_dst);
#endif
}
Скачать листинг программы в текстовом виде (2 КБ ZIP)

Примеры использования программы

Пример 1. Нужно получить RGB-компоненты для 240 цветов палитры, представляющих собой плавный переход от жёлтого к красному, и записать их в двоичный файл с именем primer_1.bin.

Устанавливаем в тексте программы следующие значения:

#define pal_len  240
#define pal_loop 0
int base_colors[]={63,63,0, 63,0,0};
#define save_mode 1
char *save_name="primer_1.bin";

После компиляции и запуска на экране будут изображены требуемые 240 цветов (рис. 1).

Рис. 1

После нажатия любой клавиши компоненты будут записаны в двоичный файл. На каждую компоненту выделяется один байт, порядок следования — r1, g1, b1, r2, g2, b2, …, r240, g240, b240:

0000: 3F 3F 00 3F 3F 00 3F 3E 00 3F 3E 00 3F 3E 00 3F
0010: 3E 00 3F 3D 00 3F 3D 00 3F 3D 00 3F 3D 00 3F 3C
0020: 00 3F 3C 00 3F 3C 00 3F 3C 00 3F 3B 00 3F 3B 00
.....................................................
02C0: 00 3F 01 00 3F 01 00 3F 01 00 3F 00 00 3F 00 00

Пример 2. Нужно получить RGB-компоненты для 200 цветов палитры с плавным переходом между следующими цветами: красный, жёлтый, зелёный, фиолетовый (причём последний цвет должен плавно переходить в первый). Полученные компоненты нужно записать в текстовый файл с именем primer_2.txt.

Устанавливаем в тексте программы следующие значения:

#define pal_len  200
#define pal_loop 1
int base_colors[]={63,0,0, 63,63,0, 0,63,0, 63,0,63};
#define save_mode 2
char *save_name="primer_2.txt";

После компиляции и запуска на экране будут изображены требуемые 200 цветов (рис. 2).

Рис. 2

После нажатия любой клавиши компоненты будут записаны в текстовый файл:

        db 63,0,0
        db 63,1,0
        db 63,3,0
        .........
        db 63,0,1

Литература

  1. А.Фролов, Г.Фролов. «Программирование видеоадаптеров CGA, EGA и VGA». М.: Диалог-МИФИ, 1992.
Страница Ивана Рощина > Статьи >