/**************************************************
 * This is a part of DosWare 3D engine and it     *
 * should be distributed freely.                  *
 *                                                *
 * Copyright (C)1997 by George Yohng/DosWare,corp.*
 **************************************************/

#define LITES       32   // количество уровней яркости
#define MAXLT (LITES-1)  // максимальное значение уровня


unsigned char c_dark[256][LITES]; //место для нашей таблицы
unsigned char palette[256][3]; //палитра, для которой считаем...

unsigned long vsqtable[256]; //это - таблица квадратов числа. её можно и не
                          //создавать, но с ней всё будет считаться быстрее

inline int _vabs(int a)  //эта функция вычисления абсолютного значения
{return (a>=0)?a:-a;}    //без излишних наворотов, т.к. универсальность
                         //нам здесь не нужна.

void calcvsqtable() //посчитаем таблицу квадратов
{int t;
 for(t=0;t<256;t++) vsqtable[t]=t*t;
}
unsigned char nearcolor(int r,int g,int b) //вот это - самая страшная функция -
                                      //нахождение ближайшего цвета в палитре
                                      //по компонентам R,G,B.
                                      //я на неё также буду ссылаться при
                                      //объяснении сглаживания и удаления
                                      //эффекта interlaced.
{
 unsigned long destm, //расстояние до ближайшего цвета
               destx; //вычисленное расстояние
 int c,  //текущий проверяемый цвет
     tc; //индекс ближайшего цвета

 if (r>MAXLT) r=MAXLT; // это для того, чтобы уровни с избыточной
 if (g>MAXLT) g=MAXLT; // яркостью не создавали возможной ситуации
 if (b>MAXLT) b=MAXLT; // переполнения, т.к. квадраты компонент
                       // берутся из фиксированной таблицы

 destm=vsqtable[_vabs(palette[0][0]-r)]+ // предположим, что ближайший
       vsqtable[_vabs(palette[0][1]-g)]+ // цвет - это цвет с индексом 0
       vsqtable[_vabs(palette[0][2]-b)]; // и вычислим расстояние до него
 tc=0;                                   // по теореме Пифагора.

 for(c=1;c<256;c++) //а теперь для каждого цвета...
 {
  destx=vsqtable[_vabs(palette[c][0]-r)]+ //
        vsqtable[_vabs(palette[c][1]-g)]+ // вычисляем расстояние...
        vsqtable[_vabs(palette[c][2]-b)]; //

  if (!destx) return c; //очевидно, что если расстояние от исследуемого
                        //до текущего цвета равно нулю, то это один
                        //и тот же цвет, дальше поиск продолжать нет
                        //смысла.

  if (destx<=destm) //и если оно меньше минимального , то...
  {
   tc=c;destm=destx; //предполагаю, что текущий цвет - ближайший.
  }
 }
 return tc; //возвращаем наилучший результат.

}// почему я в функции вычисления расстояния не вычислял квадратный корень
 // в соответствии с классической формулой? см. объяснения после текста
 // программы.


void createdrk() //и, наконец, создать таблицу.
{int c1,lt;
 vsqtable(); //подготовка таблицы квадратов...
 printf("Creating light table, please, wait...");
 fflush(stdout); //требуется для Watcom C/C++

 for(c1=0;c1<256;c1++)
 {
  for(lt=0;lt<LITES;lt++)
   c_dark[lt][c1]=nearcolor(palette[c1][0]*lt*2/LITES,
                            palette[c1][1]*lt*2/LITES,
                            palette[c1][2]*lt*2/LITES);
 }
 printf("done.\n");
}
