Galaxy2D Tutorials Галактика 2D
Полупрозрачность

Теория

Понять полупрозрачность (semi-transparency) не сложно: вся работа заключается в добавлении некого процента одного цвета к некому проценту другого цвета. К примеру, Вы хотите отобразить оттенок красного, который является на 80% непрозрачен на жёлтом. Для этого нужно лишь взять по 80% красного, зелёного и синего компонентов первого цвета (оттенок красного) и добавить 20% красного, зелёного и синего компонентов жёлтого цвета.

 

Теперь представьте, что Вам нужно отобразить растровое изображение 80х80 с полупрозрачностью. Вы были бы должны вычислять значения RGB-компонент для каждого пикселя (и, если Вы работаете с 256 цветами, необходимо было бы искать самый лучшей цвет в палитре). Это, предположите Вы, очень медленно. Поэтому, чтобы увеличить быстродействие, нам придётся немного схитрить.

 

Введение

Поскольку вычисления результирующих компонент RGB и поиск наилучшего соответствия слишком медленны в реальном масштабе времени, мы посчитаем их заранее и сохраним в 2D массиве, так называемой таблице соответствия (look-up table).

 

 

В режиме 256 цветов имеется 2562 возможных вариантов комбинации цветов для каждого уровня прозрачности. Иными словами, Вам нужно 64 килобайта для каждой таблицы. Хорошая новость: каждая таблица может использоваться для двух уровней прозрачности. Но, скажете Вы, нужны хотя бы четыре уровня, к примеру, 80%, 60%, 40% и 20%. Эта информация может быть сохранена только в двух таблицах, так как lut[a][b] хранит прозрачность для n%, а lut[b][a] для (100-n)%.

 

Код

Вот код, чтобы посчитать результирующий цвет, найти лучшее соответствие этому цвету и создать таблице соответствия. Другими словами, Вы должны использовать полупрозрачность самостоятельно. Я не привожу, кода по наложению прозрачности (blitting), так как он очень зависим от компиляторов. Но вот псевдокод для наложения прозрачности на один пиксель:

 

void PutPixelTrans(int x, int y, char col, char *lut)

{

  char bgCol;

  bgCol=GetPixel(x,y);

  PutPixel(x,y, lut[bgCol + 256*col]);

}

 

А вот остальной код:

 

/*

* Простой код для наложения полупрозрачности

* by Lennart Steinke <lennart_steinke@bigfoot.com>

*/

/* Немного определений... */

#define UBYTE           unsigned char

#define RED(pal,a)      (pal)[(a)*3+0]

#define GREEN(pal,a)    (pal)[(a)*3+1]

#define BLUE(pal,a)     (pal)[(a)*3+2]

#define SQR(x)          ((x) * (x))

/*

* best_match

* Возвращает наилучшее соответствие заданным RGB компонентам (r,g,b)

* в заданной палитре (pal).

* pal является массивом byte с размером 768 (256 *3)

*/

UBYTE best_match(UBYTE* pal, UBYTE r, UBYTE g, UBYTE b)

{   

  int result=0;

  int r2,g2,b2,a;

  unsigned long f=MAXLONG;

  int i, i2;

  i=0.3*r + 0.59*g + 0.11*b;

  for (a=0; a<256; a++)

  {

    r2=RED(pal,   a);

    g2=GREEN(pal, a);

    b2=BLUE(pal,  a);

    i2 =0.3*r2 + 0.59*g2 + 0.11*b;

    if (SQR(r2-r) + SQR(g2-g) + SQR(b2-b) + SQR(i2-i)< f)

    {

        result=a;

        f=SQR(r2-r)+SQR(g2-g)+SQR(b2-b)+SQR(i2-i);

        if (f==0) break;

    }

  }

  return (UBYTE) result;

}

/*

* CreateLUT

* Создаёт таблицу просмотра для заданной палитры (pal)

* и уровня прозрачности (alpha), возвращает указатель на таблицу

*/

UBTYE *CreateLUT(UBYTE *pal, float alpha)

{

  UBYTE r,g,b, r_,g_,b_*table;

  int actcol, overaylcol,  alpha_, pos=0;

  alpha_ = 1- alpha;

  table = (UBYTE *) malloc( 256 * 256);

  for (actcol=0; actcol  <256; actcol++)

  {

    r = RED(pal, actcol);

    g = GREEN(pal, actcol);

    b = BLUE(pal, actcol);

    for (overlaycol =0; overlaycol < 256 overlaycol ++)

    {

      r_ = r * alpha_ + RED(pal, overlaycol) * alpha;

      g_ = g * alpha_ + GREEN(pal, overlaycol) * alpha;

      b_ = b * alpha_ + BLUE(pal, overlaycol) * alpha;

      table[pos] = best_match(pal, r_, g_, b_);

        pos++;

    }

    }

}

 

В заключение

 

Я хочу поблагодарить Amit Patel за напоминание, что одна таблица содержит два уровня полупрозрачности.

Верстка и поддержка Lennart Steinke

 

PMG  10 декабря 2004 (c)  Сергей Иванов