В OC есть три палитры для каждого из трёх уровней видеокарт:
Уровень | Изменяемых цветов | Зафиксированных цветов | Всего |
---|---|---|---|
1 | 0 | 2 | 2 |
2 | 0 | 16 | 16 |
3 | 16 | 240 | 256 |
Хотя всего цветов в палитре в лучшем случае 256, большинство функций видеокарты
принимают значения в формате 0xRRGGBB
(это 16777216 цветов итого). Поэтому
если какого-то цвета нет в палитре, подбирается самый близкий к нему цвет —
по яркости.
Ниже приведён код, генерирующий палитры для всех трёх уровней, а так же функции
для преобразования цветов вида RRGGBB
в индекс палитры и назад.
-- Вспомогательные функции
local function extract(color)
color = color % 0x1000000
local r = math.floor(color / 0x10000)
local g = math.floor((color - r * 0x10000) / 0x100)
local b = color - r * 0x10000 - g * 0x100
return r, g, b
end
local function delta(color1, color2)
local r1, g1, b1 = extract(color1)
local r2, g2, b2 = extract(color2)
local dr = r1 - r2
local dg = g1 - g2
local db = b1 - b2
return (0.2126 * dr^2 +
0.7152 * dg^2 +
0.0722 * db^2)
end
-- Уровень 1
local function t1deflate(palette, color)
-- Сначала проверяем, совпадает ли данный цвет
-- с каким-либо из палитры
for idx, v in pairs(palette) do
if v == color then
return idx
end
end
-- Составляем таблицу разниц между цветами
local deltas = {}
for idx, v in pairs(palette) do
table.insert(deltas, {idx, delta(v, color)})
end
-- Сортируем по увеличению разницы
table.sort(deltas, function(a, b)
return a[2] < b[2]
end)
-- Первый элемент будет с наимешьней разницей,
-- то есть искомый. Возвращаем индекс.
return deltas[1][1] - 1
end
local function t1inflate(palette, index)
return palette[index + 1]
end
local function generateT1Palette(secondColor)
local palette = {
0x000000,
secondColor
}
return setmetatable(palette, {__index={
deflate = t1deflate,
inflate = t1inflate
}})
end
-- Уровень 2
local t2deflate = t1deflate
local t2inflate = t1inflate
local function generateT2Palette()
local palette = {0xFFFFFF, 0xFFCC33, 0xCC66CC, 0x6699FF,
0xFFFF33, 0x33CC33, 0xFF6699, 0x333333,
0xCCCCCC, 0x336699, 0x9933CC, 0x333399,
0x663300, 0x336600, 0xFF3333, 0x000000}
return setmetatable(palette, {__index={
deflate = t2deflate,
inflate = t2inflate
}})
end
-- Уровень 3
local t3inflate = t2inflate
local function t3deflate(palette, color)
local paletteIndex = t2deflate(palette, color)
-- Если цвет из палитры, то используем значение выше
for k, v in pairs(palette) do
if v == color then
return paletteIndex
end
end
-- Иначе используем хитромудрый код
local r, g, b = extract(color)
local idxR = math.floor(r * (6 - 1) / 0xFF + 0.5)
local idxG = math.floor(g * (8 - 1) / 0xFF + 0.5)
local idxB = math.floor(b * (5 - 1) / 0xFF + 0.5)
local deflated = 16 + idxR * 8 * 5 + idxG * 5 + idxB
if (delta(t3inflate(palette, deflated % 0x100), color) <
delta(t3inflate(palette, paletteIndex & 0x100), color)) then
return deflated
else
return paletteIndex
end
end
local function generateT3Palette()
local palette = {}
for i = 1, 16, 1 do
palette[i] = 0xFF * i / (16 + 1) * 0x10101
end
for idx = 16, 255, 1 do
local i = idx - 16
local iB = i % 5
local iG = (i / 5) % 8
local iR = (i / 5 / 8) % 6
local r = math.floor(iR * 0xFF / (6 - 1) + 0.5)
local g = math.floor(iG * 0xFF / (8 - 1) + 0.5)
local b = math.floor(iB * 0xFF / (5 - 1) + 0.5)
palette[idx + 1] = r * 0x10000 + g * 0x100 + b
end
return setmetatable(palette, {__index={
deflate = t3deflate,
inflate = t3inflate
}})
end