Как совместить текстуру и освещение
Прежде всего, немного теории. Нам понадобится знать то, что конечный цвет пиксела с составляющими (r,g,b) и освещенного цветом (light_r,light_g,light_b) считается как
result_r = r * light_r / max(light_r); result_g = g * light_g / max(light_g); result_b = b * light_b / max(light_b);
Здесь max(light_r) - это максимально возможное значение для light_r. Не максимальное по всем тем градациям освещенности, что мы используем, а вообще максимальное для всех возможных градаций. Например, если у нас значения для light_r могут гулять от 0 до 255, а текущий источник света имеет цвет (30, 40,50), то соответственно градации освещенности будут равны (k*30,k*40,k*50), где 0 <= k <= 1, то max(light_r) = 255, а не 30. Немного путаное объяснение, но вообще это известная и понятная почти всем вещь.
256-цветные режимы
Метод 1: заранее посчитать таблицу, переводящую пару (цвет, освещенность) в цвет. Можно не менять палитру, а искать для каждой пары (цвет, освещенность) наилучшим образом приближающий ее цвет; а можно (как описано в demo.design FAQ) взять палитру и сгенерировать из нее true color картинку 256x256, в которой пиксел (x, y) нарисован цветом (уже true color!), соответствующим цвету x и освещенности y, а потом перевести ее чем-нибудь типа Image Alchemy в 256 цветов. После чего использовать палитру получившейся картинки, а в качестве таблицы (colorTable) будет сама получившаяся картинка:
outputColor = colorTable[intensity][color].
Метод 2: если нас устроит использовать немного цветов и градаций освещения, то тогда в палитру можно впихнуть все возможные градации всех используемых цветов. Тогда определение нужного индекса в палитре - это одно умножение, а лучше - сдвиг, и одно сложение. Пример: пусть у нас есть 8 цветов и 32 градации освещенности. Палитру заполняем так: 32 градации первого цвета, второго, ..., восьмого. Тогда (для этого примера)
outputColor = (color << 5) + intensity.
24/32-битные режимы
Здесь все делается теми же самыми таблицами. Только таблица переводит не цвет в цвет, а компоненту цвета в компоненту цвета. То есть, создаем таблицы redTable[numShades], greenTable[numShades], blueTable[numShades], а потом для каждой компоненты каждого пиксела и нужной градации освещенности по этой таблице определяем выходное значение компоненты:
r = redTable[intensity], g = greenTable[intensity], b = blueTable[intensity].
Каждая компонента в этих режимах - это отдельный байт, поэтому никаких проблем не возникает.
15/16-битные режимы
Метод 1: тупой, но действенный. Использовать большую таблицу и занести в нее все возможные комбинации цвета и градации освещения. Таблица получится совсем не маленькая, размером 65536*32 = 2 мегабайта. Я написал здесь 32, потому как в этих режимах на компоненту отводится по 5 бит (за исключением 6-битной зеленой компоненты в 16-битном режим), и делать больше градаций освещенности, чем 32, бессмысленно.
Метод 2: делать все так же, как в 24/32-битных режимах. Проблемы возникнут из-за того, что придется с муками выдирать нужные несколько бит компоненты из пиксела. Таблицы для компонент лучше заранее сделать со всеми нужными сдвигами, т.е. значения элементов таблиц должны быть такого вида:
000bbbbb - синий, 8 бит 00000gggggg00000 - зеленый, 16 бит rrrrr000 - красный, 8 бит
Тогда конечный цвет считается примерно так:
outputColor = (redTable[(color >> 10) & 0x2F] << 8) + greenTable[(color >> 5) & 0x1F] + blueTable[color & 0x1F].
На ассемблере это делается, видимо, побыстрее - и покрасивее. Примерно так:
; ... mov bx,color shr bx,10 and bx,02Fh mov ah,redTable[bx] mov bx,color and bx,01Fh mov al,blueTable[bx] mov bx,color shr bx,5 ; можно заменить на and bx,01Fh ; shr bx,4 shl bx,1 ; and bx,02Eh or ax,greenTable[bx] mov outputColor,ax ; ...
Метод 3: рисовать все в 24/32-бита, освещение соответсвенно с текстурой совмещать по пункту 5.6.2, а потом непосредственно при выводе на экран делать преобразование из 24/32-бит в 15/16. Или использовать PTC и предоставить делать нужное преобразование именно ему. PTC - это такая графическая система для C++, взять ее можно на www.gaffer.org/ptc.
1 2 3 4
8 8 8
| |