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

Как убрать чёрные полосы по краям экрана OpenComputers

Рекомендуемые сообщения

На днях в чате прозвучал вопрос, как убрать чёрные полосы по краям экрана. На форуме есть замечательная библиотека от @ECS, которая хорошо решает поставленную задачу: http://computercraft.ru/topic/1130-avtomaticheskii-mssahtab-monitora-izbavliaemsia/

Но есть два нюанса:

1) Код библиотеки явно избыточен.

2) При чтении кода библиотеки создаётся впечатление, что она работает на неведомой магии тёмных сил, что демотивирует новичков, изучающих OpenComputers.

Я намерен восполнить данный недостаток.

 

Прочтение этого гайда поможет любому желающему написать кусочек кода под нужды конкретной программы, не подтягивая библиотечный код.

 

Благодарю @Totoro за предоставленную информацию:

1) Текстура блока имеет размер 16 px, а ширина рамки монитора – 2 px;

2) Высота символа на экране в два раза больше его ширины.

Данной информации достаточно для получения всех необходимых формул. Приступим:

 

Первый шаг: получить соотношение сторон экрана, выраженное в символах

 

В мире Майнкрафта текстура блока имеет размер в 16 пикселей. На рамку с каждой стороны тратится по 2 пикселя независимо от размера монитора.

Pdqexqc.png

 

Очевидно, что размер монитора в пикселях кратен 16 и пропорционален количеству использованных блоков, а размер полезной части экрана всегда меньше размера монитора на 4 пикселя как по вертикали, так и по горизонтали. Поэтому разрешение нескольких мониторов, выставленных в ряд, всегда составит 16*n-4 пикселей по соответствующей координатной оси.

 

Это подтверждает и формула от @ECS, реализованная в функции calculateAspect(screens), но имеющая более сложный вид. Я предлагаю и вовсе отказаться от отдельной функции, т. к. в текущих условиях это будет напрасной тратой ресурсов.

 

Немного поясняющего кода:

-- размер монитора в блоках
sw,sh = component.screen.getAspectRatio()
-- размер экрана монитора с учётом затрат на рамку:
sw_ = sw*16-4
sh_ = sh*16-4
-- соотношение сторон экрана, выраженное в пикселях текстуры блока
sa = sw_/sh_
-- соотношение сторон экрана, выраженное в символах
sa = 2*sw_/sh_
-- оно же без промежуточных присваиваний:
sa = 2*(sw*16-4)/(sh*16-4)
-- оно же после упрощения формулы и сокращения количества операций
sa = (sw*2-0.5)/(sh-0.25)

Второй шаг: скорректировать разрешение графической карты под соотношение сторон экрана

 

Теперь требуется получить максимально доступное разрешение GPU и соответствующее ему соотношение сторон:

-- максимально возможное разрешение графической карты в символах
gw, gh = gpu.maxResolution()
-- соотношение сторон при максимальном разрешении в символах
ga = gw/gh
-- формулы, полученные из предыдущей, и которые пригодятся чуть позже
gw = gh*ga
gh = gw/ga

Для определения дальнейших действий следует вспомнить о физическом смысле соотношения сторон. Исходя из приведённых выше формул, sa и ga можно назвать коэффициентами горизонтальности. Сравнивая их, можно определить, что по горизонтали более вытянуто разрешение либо видеокарты, либо монитора. Понятно, что если монитор имеет больший коэффициент горизонтальности, то для приведения к нему коэффициента горизонтальности видеокарты следует уменьшить её разрешение по вертикали. В ином случае следует уменьшать разрешение GPU по горизонтали:

-- код в понятной форме, использованы формулы из предыдущего фрагмента
if sa>ga then -- недостаточная горизонтальность GPU
  ga=sa -- привести горизонтальность в соответствии с экраном
  gh = gw/ga -- за счёт уменьшения высоты
else -- избыточная горизонтальность GPU
  ga=sa -- привести горизонтальность в соответствии с экраном
  gw = gh*ga -- за счёт уменьшения ширины
end
-- код после сокращения лишних операций
if sa > gw/gh then
  gh = gw/sa
else
  gw = gh*sa
end

Третий шаг: скорректировать разрешение графической карты под нужны программы

 

Вычисленное на предыдущем шаге разрешение может оказаться дробным, и перед использованием его следует округлить. Возможно, что перед этим разрешение должно быть приведено к желаемому масштабу, как это сделано в библиотеке @ECS. Эта часть, скорее всего, не требует пояснений, и готовый код будет, например, таким:

-- код для автоматической подстройки разрешения графической карты под размер монитора
--  почти не оставляет чёрных полос по краям экрана
--  полное исключение полос возможно только при отсутствии округления разрешения

local component = require"component"
local gpu, screen = component.gpu, component.screen

function set_proportional_resolution( scale )
  -- коррекция допустимых пределов масштаба
  if not scale or scale > 1 then
    scale = 1
  elseif scale < 0.1 then
    scale = 0.1
  end
  -- соотношение сторон монитора в символах:
  local sw,sh = screen.getAspectRatio()
  local sa = (sw*2-0.5)/(sh-0.25)
  -- запрос и коррекция максимального разрешения GPU
  local gw, gh = gpu.maxResolution()
  if sa > gw/gh then
    gh = gw/sa
  else
    gw = gh*sa
  end
  -- установка нового разрешения GPU с учётом заданного масштаба
  gpu.setResolution( math.floor(gw*scale), math.floor(gh*scale) )
end

-- тест работоспособности на нескольких вариантах масштаба
-- в процессе можно видеть, что на некоторых масштабах чёрные полосы имеют больший размер, чем на других
local w,h
local unicode = require"unicode"

for i=0.1, 1, 0.1 do
  set_proportional_resolution(i)
  w,h = gpu.getResolution()
  gpu.fill(1,1,w,h, unicode.char(0x2592))
  os.sleep(2)
end

Приведённый код можно сократить ещё сильнее, например, избавившись от масштабирования, которое может отвлекать читателя от подгонки соотношения сторон.

 

Полное исключение чёрных полос

 

При выполнении этого кода можно видеть, что чёрные полосы не исчезают полностью, и на одних масштабах проявляются сильнее, чем на других. Предположим, требуется полностью избавиться от чёрных полос. Можно было бы написать код и для этого случая, но эта задача не всегда решаема. Кроме того, количество решений сильно ограничено, и не любой интерфейс можно будет подогнать под найденные решения.

 

Пример №1:

Монитор максимального допустимого размера 8x6; GPU Tier3 обеспечивает максимальное разрешение 160x50.

Условное разрешение монитора в целых символах:

sw = 8*8-2 = 62

sh = 6*4-1 = 23

Допустимые разрешения GPU, которые обеспечат отсутствие полос: 62x23 и 124x46.

 

Пример №2:

Монитор 6x5; GPU Tier1 обеспечивает максимальное разрешение 50x16.

Условное разрешение монитора в целых символах:

sw = 6*8-2 = 46

sh = 5*4-1 = 19

Нет разрешений GPU, обеспечивающих полное отсутствие полос.

 

Пример №3:

Монитор 5x5; GPU Tier1 обеспечивает максимальное разрешение 50x16.

Условное разрешение монитора в целых символах:

sw = 5*8-2 = 38

sh = 5*4-1 = 19

Разрешения GPU 50x16 недостаточно для размещения поля символов 38x19. Но если присмотреться внимательно, и вспомнить, что нам важно соотношение, то поле символов можно сократить до 2x1, избавившись от общего делителя 19. В этом случае допустимых разрешений GPU предостаточно, начиная от 2x1 и заканчивая 32x16. Во всех этих случаях пустых чёрных полос на мониторе не будет.

 

Автоматизация этих вычислений вряд ли целесообразна. Скорее всего, имеет смысл примерно прикинуть необходимое разрешение для конкретного интерфейса, выбрать желаемый размер экрана, графическую плату, и выполнив приведённые выше вычисления, уже окончательно определить рабочее разрешение и затем подогнать интерфейс под него.

 

 

Вот, и вся магия. То, что выглядит сложным, не всегда является таковым на самом деле.

 

Upd: Дополняющий гайд от @ECS:

https://computercraft.ru/topic/2501-kak-ubrat-chyornye-polosy-po-krayam-ekrana-v30/

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Чтобы потом долго не искать, я оставлю заметку в этой теме.

 

Как нам поведал внимательный @Fingercomp, полная ширина рамки составляет не 2 px, а 2.25 px, поэтому идеальная пропорция разрешения экрана в символах будет составлять 2*(16w-4.5) / (16h-4.5). Чёрная рамка шириной 1/4 px сохраняется всегда, избавиться от неё невозможно.

 

Также @Fingercomp очень подробно разобрал пример поиска оптимального разрешения экрана, минимизируя разницу в ширине вертикальной и горизонтальной полос. Код поиска оптимума выложен здесь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поиск идеальных соотношений сторон монитора.

 

Задача: найти такие конфигурации мониторов, для которых существуют  разрешения, при которых ширина вертикальной и горизонтальной чёрной рамки одинакова.

 

Очевидно, что для квадратных мониторов существует множество разрешений, удовлетворяющих заданному условию. Достаточно, чтобы разрешение по горизонтали было вдвое больше разрешения по вертикали. Но количество возможных решений для мониторов с конфигурациями, отличающимися от квадрата, сильно ограничено. Более того, идеальное разрешение существует не для всех конфигураций мониторов.

 

Для поиска решений я буду использовать перебор всевозможных разрешений, благо, их не так много.

-- Вычисление идеальных разрешений для мониторов разных размеров
-- Не проверяются квадратные мониторы с размерами 1x1, 2x2, 3x3 и т.д.

-- максимальный размер монитора
local msw,msh = 8,6
-- максимальное разрешение GPU
local max_gpu_res, max_gpu_area = 160, 160*50
-- максимальная ошибка, допустимая при округлении разрешения по вертикали
local max_error = 1e-3

-- перебор всех допустимых размеров мониторов кроме квадратных
for sw = 1, msw do
  for sh = 1, msh do
    if sw~=sh then
      local ratio_wh = 2*(16*sw-4.5)/(16*sh-4.5)
      -- перебор всех разрешений монитора
      for gw = 1, max_gpu_res do
        local gh_float = gw / ratio_wh
        local gh = (gh_float+0.5)//1
        -- печать допустимых разрешений с ошибкой в пределах погрешности
        if math.abs(gh_float-gh) <= max_error
          and gh <= max_gpu_res
          and gh*gw <= max_gpu_area then
          print( ("%dx%d: %dx%d=%d (%2.0f%%)\terror=%.0e"):format(
            sw,sh, gw,gh,gw*gh,gw*gh/max_gpu_area*100, gh_float-gh ))
        end
      end
    end
  end
end

Найденные решения:

1x2: 46x55=2530 (32%)    error=7e-15
1x3: 46x87=4002 (50%)    error=0e+00
1x4: 46x119=5474 (68%)    error=0e+00
1x5: 46x151=6946 (87%)    error=0e+00
2x1: 110x23=2530 (32%)    error=0e+00
3x6: 58x61=3538 (44%)    error=0e+00
6x3: 122x29=3538 (44%)    error=0e+00
7x2: 86x11=946 (12%)    error=0e+00

Как видно, выбор среди идеальных конфигураций невелик. Найдено 5 вертикальных конфигураций и 3 горизонтальные.

 

При этом наиболее полное использование возможностей монитора (87% от максимального разрешения) имеет вертикальный монитор размером 1x5. А остальные и того меньше. Стоит ли жертвовать площадью экрана ради максимального уменьшения ширины рамки?

 

Скорее всего, большинство пользователей не захочет микрометром выверять толщину рамки и воспользуется кодом от @ECS, максимизируя разрешение.

 

Все остальные варианты будут разной степени компромиссом между максимальным разрешением и минимальными рамками. Например, @Fingercomp минимизировал ширину полос для монитора 8x3, и получил разрешение, близкое к максимально возможному для выбранной конфигурации. Для других конфигураций выбор может оказаться более сложным, что легко увидеть на примере монитора 1x2:

1x2: 46x55=2530 (32%)    error=7e-15
1x2: 51x61=3111 (39%)    error=-2e-02
1x2: 56x67=3752 (47%)    error=-4e-02
1x2: 77x92=7084 (89%)    error=7e-02

 

Итог: Существуют идеальные соотношения сторон монитора, обеспечивающие равную ширину вертикальных и горизонтальных чёрных полос по краям изображения. Но таких вариантов очень мало, а их практическая применимость маловероятна.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...