Перейти к содержимому






Фотография
* * * * * 3 голосов

Палитры OpenComputers

Написано Fingercomp , в OpenComputers, Programming in Lua, Tutorials 19 Апрель 2017 · 788 просмотров

палитра OpenComputers palette цвет color gpu gui OC

Немногие знают, как работают палитры в OpenComputers. Расскажу здесь, как избавиться от необходимости прописывать гектары цветов в палитре, покажу, как упаковываются цвета в OpenComputers и дам пару алгоритмов для работы с индексами.

 

Сразу условимся, что индексы палитр у нас будут начинаться с нуля.

 

На каждой из трёх уровней видеокарт и мониторов своя поддерживаемая палитра цветов. Будем двигаться снизу вверх.

 

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

 

Для определения разницы между цветами здесь и далее используется функция delta. Вот как она выглядит (вместе с функций extract, выделяющей из числа вида 0xABCDEF числа 0xAB, 0xCD, 0xEF):

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
Теперь можно конвертировать цвет в индекс палитры. Суть такова: выбираем из двух цветов ближайший и возвращаем его.
local palette = {
  0x000000,
  CONFIG.monochromeColor
}

local function t1deflate(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.append(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(index)
  return palette[index + 1]
end
Как и говорил.

 

Второй уровень
В палитре второго уровня имеется 16 закреплённых цветов:

local palette = {0xFFFFFF, 0xFFCC33, 0xCC66CC, 0x6699FF,
                 0xFFFF33, 0x33CC33, 0xFF6699, 0x333333,
                 0xCCCCCC, 0x336699, 0x9933CC, 0x333399,
                 0x663300, 0x336600, 0xFF3333, 0x000000}
В остальном конвертация из иднекса в цвет и из цвета в иднекс аналогична алгоритмам для первого уровня. Так как они были даны в общем виде, код для них тот же самый.
local t2deflate = t1deflate
local t2inflate = t1inflate
Третий уровень
Палитра третьего уровня содержит уже 256 цветов: первые 16 цветов изменяются, а остальные соответствуют цветам палитры RGB-6-8-5. Это означает, что можно смешивать 6 оттенков красного, 8 оттенков зелёного и 5 оттенков синего. В общем-то, довольно очевидна причина такого выбора: человеческий глаз лучше всего различает оттенки зелёного и хуже всего - оттенки синего.

 

В любом случае, здесь алгоритмец будет посложнее. Сначала нужно сгенерировать палитру.
Начнём с первых 16 цветов. Они не включаются в палитру RGB-6-8-5, поэтому их заполнять нужно отдельно. В OpenComputers по умолчанию они содержат оттенки серого. Так как чёрный и белый уже включены в основную, зафиксированную палитру, то заново их дублировать смысла нет.

local palette = {}

-- grayscale
for i = 1, 16, 1 do
  palette[i] = 0xFF * i / (16 + 1) * 0x10101
end
Таким образом в таблице получаются следующие оттенки серого:
0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78,
0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2, 0xE1, 0xF0
Эти цвета мы записываем в индексы от 0 до 15. Теперь нужно сгенерировать остальные цвета - они не изменяются. Здесь будет посложнее.
Посмотрим на картинку с палитрой:
Изображение
В OpenComputers левая верхняя ячейка палитры (0x000000) имеет индекс 16, а правая нижняя (0xFFFFFF) имеет индекс 255. Индексы распределяются слева направо, сверху вниз. То есть правая верхняя ячейка (0x00FFFF) имеет индекс 55, а вторая сверху и левая (0x330000) - это номер 56. Отсюда вытекает следующий алгоритм нахождения цвета: сначала найти индексы отдельно по R, G, B, затем для каждого из этих трёх индексов найти соответствующий ему оттенок цвета, а затем всё сложить.
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
К слову сказать, math.floor(x + 0.5) - это округление до ближайшего целого.

 

Всё. Палитра есть, теперь можно, наконец-то, конвертировать индексы между цветами.
Из индексов получить цвет довольно просто. Достаточно использовать ту же функцию, что и для предыдущих уровней:

t3inflate = t2inflate
С обратной же конвертацией всё в разы сложнее. Функция, используемая в OC, подбирает ближайший цвет очень хитрым алгоритмом, который я привожу ниже.
local function t3deflate(color)
  local paletteIndex = t2deflate(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(deflated % 0x100), color) <
      delta(t3inflate(paletteIndex & 0x100), color)) then
    return deflated
  else
    return paletteIndex
  end
end
В общем-то, это всё. Показал портированный со Scala на Lua код, который используется в OpenComputers. С помощью этого можно оптимизировать операции с экраном, выбирая поддерживаемые монитором цвета. И заодно избавиться от таблиц цветов, которые некоторые буквально берут и копипастят в файл, даже не задумываясь об изменяемых цветах палитры.
Особенно это важно, когда берётся значение цвета через gpu.get, потому что следующий код всегда вернёт false:
local gpu = require("component").gpu

gpu.setForeground(0x20AFFF)
gpu.setBackground(0x20AFFF)
gpu.set(1, 1, "HI")

return select(2, gpu.get(1, 1)) == 0x20AFFF
И всё потому, что gpu.get возвращает уже приведённый к индексу из палитры цвет. А 0x20AFFF в палитре, если не менять первые 16 цветов, не имеется.

 

Enjoy :P






Фотография
electronic_steve
19 апр 2017 18:32

также палитра позволяет делать так
 

    • Totoro, Fingercomp, ECS и еще 1 это нравится

Отлично! Давно хотел написать статью по работе с цветом. А теперь можно просто оставить ссылку, т. к. все основы хорошо разобраны.

23 оттенка зеленого:
6w26ire.png
    • Totoro и Fingercomp это нравится

Обратные ссылки на эту запись [ URL обратной ссылки ]

Обратных ссылок на эту запись нет

Последние версии

Стабильная: 1.7.1
Последняя: 1.7.1

Искать в моем блоге

Новые комментарии

Январь 2018

В П В С Ч П С
 123456
78910111213
14151617 18 1920
21222324252627
28293031   

Полезные ссылки

Официальный сайт OpenComputers

http://oc.cil.li/

 

Официальный форум OpenComputers

http://oc.cil.li/index.php?/index

 

Репозиторий OpenComputers на ГитХабе

https://github.com/M...s/OpenComputers

 

Последние релизы OpenComputers

https://github.com/M...puters/releases

 

Jenkins-сервер

http://ci.cil.li/job...s-dev-MC1.7.10/
 

Репозиторий OpenPrograms

https://github.com/OpenPrograms

 

Репозиторий моих программ

https://github.com/O...rcomp-Programs/

2 посетителей

0 пользователей, 0 гостей, 0 анонимных


Google (1), Yandex (1)

Последние посетители

  • Фотография
    VGAMER_Tiger
    Вчера, 16:54
  • Фотография
    AtomicScience
    16 янв 2018 - 21:31
  • Фотография
    RockMaks_00
    15 янв 2018 - 10:07
  • Фотография
    DotPack
    15 янв 2018 - 01:04
  • Фотография
    Mirotworex
    14 янв 2018 - 23:46
  • Фотография
    Koteyk0o
    14 янв 2018 - 05:03
  • Фотография
    Totoro
    13 янв 2018 - 16:03
  • Фотография
    HixOff
    11 янв 2018 - 22:49
  • Фотография
    Kartograf
    11 янв 2018 - 17:47
  • Фотография
    MrSnake20_15
    10 янв 2018 - 16:52
  • Фотография
    Belzebub
    10 янв 2018 - 16:12
  • Фотография
    LeshaInc
    10 янв 2018 - 09:24
  • Фотография
    MeXaN1cK
    10 янв 2018 - 00:31
  • Фотография
    Megageorgio
    09 янв 2018 - 22:16
  • Фотография
    IS2511
    09 янв 2018 - 17:50
  • Фотография
    RccHD
    08 янв 2018 - 06:32
  • Фотография
    qwertyMAN
    08 янв 2018 - 03:03
  • Фотография
    Litvinov
    07 янв 2018 - 20:34
  • Фотография
    Sharplook
    07 янв 2018 - 14:50
  • Фотография
    eu_tomat
    06 янв 2018 - 20:11
  • Фотография
    Pa3eP
    06 янв 2018 - 05:32
  • Фотография
    FluttyProger
    05 янв 2018 - 23:45
  • Фотография
    rrr_game
    04 янв 2018 - 21:59
  • Фотография
    MnxCool
    04 янв 2018 - 15:33
  • Фотография
    Appo
    03 янв 2018 - 12:21
  • Фотография
    Bencod
    02 янв 2018 - 19:39
  • Фотография
    Laine_prikol
    02 янв 2018 - 17:39
  • Фотография
    ECS
    31 дек 2017 - 19:25
  • Фотография
    folder
    29 дек 2017 - 16:13
  • Фотография
    JLevi
    29 дек 2017 - 07:55
  • Фотография
    ArtemGP
    28 дек 2017 - 16:39
  • Фотография
    Doob
    27 дек 2017 - 14:40
  • Фотография
    Quant
    27 дек 2017 - 10:30
  • Фотография
    Kid
    26 дек 2017 - 23:51
  • Фотография
    vovaluzancomp
    26 дек 2017 - 20:38
  • Фотография
    Nova
    26 дек 2017 - 15:17
  • Фотография
    Electronix205
    26 дек 2017 - 14:26
  • Фотография
    Vestalfa
    26 дек 2017 - 00:03
  • Фотография
    Arseniy10
    25 дек 2017 - 20:16
  • Фотография
    monkey
    25 дек 2017 - 14:39
  • Фотография
    ivan52945
    25 дек 2017 - 02:53
  • Фотография
    NEO
    24 дек 2017 - 19:12
  • Фотография
    vx13
    24 дек 2017 - 18:07
  • Фотография
    mrGreen
    21 дек 2017 - 17:58
  • Фотография
    DarthWirthe
    20 дек 2017 - 22:07
  • Фотография
    1Ridav
    15 дек 2017 - 17:52
  • Фотография
    electronic_steve
    15 дек 2017 - 17:45
  • Фотография
    serafim
    15 дек 2017 - 14:45
  • Фотография
    Zabqer
    15 дек 2017 - 08:41
  • Фотография
    FelixBanan
    14 дек 2017 - 23:20

Лицензия

Яндекс.Метрика