OberonCore
https://forum.oberoncore.ru/

Anti-Grain для Ports
https://forum.oberoncore.ru/viewtopic.php?f=23&t=3980
Страница 4 из 6

Автор:  Димыч [ Суббота, 14 Декабрь, 2013 13:10 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

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

Автор:  Димыч [ Среда, 25 Декабрь, 2013 16:34 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Загружены файлы, достаточные для работы простыми (однопиксельными) фигурами.
https://github.com/dmitrys99/BBAGG
Веду работу над механизмом отображения шрифтов/букв.
Проведена работа по исключению избыточного импорта SYSTEM.

Автор:  Пётр Кушнир [ Среда, 25 Декабрь, 2013 20:53 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

AggTest не компилируется из-за AggWin32Bmp.
AggWin32Bmp не компилируется из-за отсутствия AggBasics.agg_getbyte.

Автор:  Димыч [ Четверг, 26 Декабрь, 2013 04:14 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Пётр Кушнир писал(а):
AggTest не компилируется из-за AggWin32Bmp.
AggWin32Bmp не компилируется из-за отсутствия AggBasics.agg_getbyte.

Fixed, commited.

Автор:  Пётр Кушнир [ Четверг, 26 Декабрь, 2013 20:37 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Работает.

Автор:  Иван Денисов [ Четверг, 26 Декабрь, 2013 21:11 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Скачал, скомпилировал, получил t.bmp

Автор:  Евгений Темиргалеев [ Воскресенье, 29 Декабрь, 2013 16:31 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Обсуждение Anti-Grain для OpenGL сборки перенесено: viewtopic.php?f=23&t=4906&p=84801#p84801

Автор:  Димыч [ Понедельник, 30 Декабрь, 2013 07:58 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

http://oberoncore.ru/projects/bbagg
Добавил карточку проекта.
Пока пусто, по мере работы буду наполнять.

Автор:  Димыч [ Понедельник, 30 Декабрь, 2013 10:09 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

По мотивам вот этого обсуждения сделал небольшой генератор, который складывает все предварительно инициализированные массивы в один модуль.
См. AggData.

Автор:  Димыч [ Вторник, 14 Январь, 2014 04:54 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Столкнулся с серьезными различиями в подходах к обработке массивов в AGG, AggPas и ББ.
Работа застопорилась на модулях обработки шрифтовой информации, их придется перепроектировать, чтобы реализовать на ББ; в коде на С++ используются шаблоны, а в коде на Паскале — большое количество нетипизированного копирования в памяти.
Поэтому в качестве временного решения я делаю dll, которая фактически реализует интерфейс Ports.Rider, чтобы подменить HostPorts.

Код библиотеки опубликую чуть позже, а пока такой вопрос, коллеги:
В модуле Ports есть несколько констант, определяющих цвета, например red, grey75 и др. Значения цвета для этих констант состоят из трех (младших) байт четырехбайтного значения. Старший байт может быть использован для прозрачности. Для того, чтобы использовать прозрачность (а она иногда бывает нужна), есть несколько путей:

  • Изменить значения цветов, заданные в Ports и установить старший байт в 0FF.
  • Завести переменную Ports.useOpacity, которая позволит интерпретировать значение прозрачности цвета (это сохранит значения для цветов в неизменном виде).
  • Совсем не использовать понятие прозрачности и не менять интерфейсы ББ, а то, что может потребоваться в графическом движке для реализации прозрачности, оставить в HostPorts.

Собственно вопрос в том, как поступить с графической подсистемой базовой версии?

Для своих продуктов, скорее всего, я буду менять интерфейсы и значения цветов (вариант 1).

Автор:  Пётр Кушнир [ Вторник, 14 Январь, 2014 09:38 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Димыч писал(а):
Для того, чтобы использовать прозрачность (а она иногда бывает нужна), есть несколько путей:

Изменить значения цветов, заданные в Ports и установить старший байт в 0FF.
Завести переменную Ports.useOpacity, которая позволит интерпретировать значение прозрачности цвета (это сохранит значения для цветов в неизменном виде).
Совсем не использовать понятие прозрачности и не менять интерфейсы ББ, а то, что может потребоваться в графическом движке для реализации прозрачности, оставить в HostPorts.
Есть еще один путь, я его рассмотрел в статье http://obertone.ru/doku.php?id=bbextendnohost
Используя подобный способ минимального расширения можно избавиться от необходимости ломать совместимость.
А цвета с нулевым значением прозрачности использовать только в режиме совместимости.

Автор:  Димыч [ Среда, 22 Январь, 2014 07:24 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Работа продолжается. Поскольку я хочу сохранить интерфейсы по возможности нетронутыми, реализация процедуры Rider.MarkRect вылилась в микрорасследование :)

Во-первых, в процедуре не используется параметр show. Сначала, видимо, хотели использовать одну технику для создания масок, но потом стали использовать голый WinAPI и отказались от этой затеи. Хозяйке на заметку.

Во-вторых, режимы Ports.invert и Ports.hilite обрабатываются одинаково, т.е. выполняется инвертирование заданного прямоугольника.

Но самое интересное — это реализация заливки прямоугольника с помощью шаблонов Ports.dimXX, где XX это {25, 50, 75}.

Пометка прямоугольника реализована с помощью функции WinApi.PatBlt, которая получает на вход прямоугольник и шаблон, а также номер одной из композитных функций, в случае MarkRect это «xor».

Сама по себе идея композитных функций проста — берется три изображения: исходное, шаблон и их функция, и к ним в разном порядке применяются битовые операции. Тема эта в MSDN хоть и раскрыта, но все же весьма туманна. Сначала я пошел по тому же пути. Попытался разобраться, как происходит применение функций и к чему, с тем, чтобы получить тот же функционал, но уже средствами AGG.

На деле оказалось, что композитные функции — такая нетривиальная штука в реализации и в общем виде (как это сделано в AGG) их использовать весьма непросто. Поэтому после двух дней экспериментов я вернулся к тому, что у меня есть битовая карта и я могу напрямую манипулировать битами.

Что имеем?
Имеем битовую карту, о построении изображения на которой в общем случае мы ничего не знаем. Делаю эту пометку специально, поскольку если бы мы могли перестроить изображение по требованию, можно было бы не модифицировать битовую карту, а накладывать поверх изображения маску и, когда нужно убрать пометку (т.е. когда MarkRect вызывается повторно с теми же параметрами), просто перерисовывали бы изображение. Можно сохранять изображение в промежутках, но это требует определенных ресурсов. Кроме того, это не избавляет от того, что изображение может быть модифицировано после наложения маски.

Поэтому я пришел к выводу, что надо пока использовать тот же механизм, что и PatBlt, но немного модифицировать его для получения визуально привлекательного результата.

Это вылилось в такую реализацию.

Инверсия прямоугольника достигается путем инверсии составных частей пикселей исходного изображения, т.е. каждого элемента триады BGR (в Windows используется именно такой порядок следования байт в пикселе).

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

В HostPorts используются 4 маски. Это упомянутые уже dimXX и focusPat, которая представляет собой косую штриховку и используется в модулях HostMechanisms и OleClient.

На стороне ББ из библиотеки AggLib вызываются две функции invert_rect и xor_rect, которые реализуют и реализуют функционал MarkRect. Можно было бы полностью реализовать MarkRect на стороне AggLib, но мне хочется сохранить возможность контролировать цвет(а) масок, поэтому MarkRect переписывается средствами BB.

---

Сейчас все принципиальные вопросы разрешены и я занимаюсь доводкой библиотеки LibAgg до состояния, в котором ее уже можно будет опубликовать. После этого буду делать подмену HostPorts и HostFonts.

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

Перенос LibAgg на другую платформу (ОС) сведется к следующим модификациям:
* изменение порядка следования цветов в пикселе;
* изменение механизма отображения битовой карты на экране (сейчас это делается средствами WinAPI).

Поэтому, принципиально, есть точки роста и для OpenGL, и для SDL, если возникнет такая необходимость.

Автор:  Пётр Кушнир [ Среда, 22 Январь, 2014 15:17 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Технически, в OpenGL для MarkRect есть свой stipple с паттернами и расцветкой.
http://www.opengl.org/sdk/docs/man2/xht ... tipple.xml так что если целевая платформа будет OpenGL то можно не нагружать Agg лишним. Но в целом норм опыт.

Автор:  Димыч [ Понедельник, 27 Январь, 2014 17:05 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Добрый вечер, коллеги!

Публикую библиотеку AGGLib, предназначенную для подмены HostPorts и HostFonts.

Код библиотеки доступен по адресу https://github.com/dmitrys99/agglib

Компилированная версия: http://pro.dimina.ru/dl/agglib.zip. Внутри dll и языковая привязка, а также тестовый модуль.

Лицензия BSD.

Использование и тестирование:
DLL кладется рядом с blackbox.exe, запускаются модули AggLib и AggTest3. В AggTest3 имеется единственная экспортированная процедура tst1, которая генерирует *.bmp-файл.

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

Обращаю ваше внимание, что почти все процедуры используют координаты с плавающей запятой (кроме Scroll); все координаты в пикселях.

Пока не реализованы процедуры отображения поверхности на HDC и draw_path. Первая будет сделана в процессе подмены подсистемы Host, вторая будет сделана по аналогии с draw_line, пока просто опущена.

За качество C++ кода не ручаюсь, я в нем сильно не разбираюсь.

Очень интересно оказалось реализовывать работу с текстами, про это напишу отдельно, там еще одно «расследование» получилось, пришлось немного модифицировать AGG.

Автор:  Димыч [ Вторник, 28 Январь, 2014 20:20 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Ну слушайте, универсальные единицы — это что-то :?
Для того, чтобы добраться до размера шрифта в точках нужно через такое продраться!

Всю логику HostFonts придется переписывать из-за этих единиц...

Автор:  adva [ Среда, 29 Январь, 2014 01:21 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

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

Автор:  Димыч [ Среда, 29 Январь, 2014 06:36 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

adva писал(а):
Может есть возможность хотя бы схематично описывать, как сейчас реализовано, и как планируешь сделать?

В условиях ограничения ресурсов хочется побольше сделать :)

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

Позже перенесу это в свой блог, переоформив в виде законченных статей.
----
Введение

Началось все с того, что, в ББ, как и в других программах для Windows, ужасная графика. Связано это, в первую очередь, с тем, что таковы реалии WinAPI. Для получения визуально привлекательного результата штатными средствами Windows нужно очень постараться. До появления GDI+ программирование векторной графики Windows было нетривиальным занятием. Связано это, на мой взгляд, с необходимостью для MS реализовывать универсальное решение. Большинство графических пакетов, вроде Aldus (Adobe) PageMaker, так или иначе использовали собственные графические движки.

Тем не менее, для программ, в которых графика не является основным назначением, выбора не было, приходилось пользоваться WinAPI.

Соответственно, для работы с графикой ББ опирается на WinAPI, конкретнее, на систему GDI.
Как она работает?

(знающие люди могут меня покритиковать, объяснение будет очень схематичным)

Каждое окно в системе имеет т.н. контекст устройства, или device context, он же DC. Можно представить DC как структуру данных, содержащих ссылки на:

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

Подробности можно посмотреть в MSDN.

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

Можно создавать заэкранные контексты устройств (без привязки к окнам), равно как и заэкранные битовые карты.

Вернемся к ББ.

Для целей работы с графикой подсистема HostPorts реализует операции с битовыми картами. Причем, эти битовые карты могут как быть связаны с окнами, там и могут быть оделены от окна (заэкранные карты).

Каждому порту сопоставляется контекст устройства (при создании или инициализации), затем все операции уже проводятся на этом контексте устройства. Если контекст устройства связан с окном, то манипуляции на контексте сражу отображаются в окне. Но это не обязательно.

В чем состоит суть тех изменений, которые я провожу?

Я написал библиотеку, которая моделирует контекст устройства. Благодаря простоте набора графических операций в ББ, эта работа относительно несложная.

Итак, с помощью библиотеки AGG я сделал библиотеку, которая реализует операции, за которыми HostPorts обращается к WinAPI, это, например, draw_line или invert_rect. Эти операции производят манипуляции на битовой карте, не связанной с DC. И если в случае с WinAPI все манипуляции с контекстом сразу могут быть отображены на контексте, то в моем случае все сводится копированию битовой карты из памяти на контекст.

Конечно, от WinAPI совсем отказаться не получится, мы же в Windows всё-таки работаем, да это и не нужно. Но фактически все операции сводятся к инициализации собственной битовой карты и последующему копированию ее на DC. В теории все просто :)

Поэтому текущая работа по подмене HostPorts состоит в том, чтобы заменить процедуры, обращающиеся к WinAPI (и вспомогательные) на собственные и изменить цепочку вызовов, обрабатывающих обновление окна так, чтобы использовалась битовая карта не из контекста устройства.

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

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

Автор:  Пётр Кушнир [ Среда, 29 Январь, 2014 10:16 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

А битмап у вас представлен в платформонезависимом виде или тоже в виде дескриптора (со скрытой структурой)?

Автор:  Димыч [ Среда, 29 Январь, 2014 16:31 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Графика со сглаживанием

То, о чем пойдет речь дальше, хорошо иллюстрирует эта картинка:
Вложение:
Комментарий к файлу: С сайта antigrain.com
agg1_01.jpg
agg1_01.jpg [ 36.86 КБ | Просмотров: 12424 ]


В GDI линии рисуются без сглаживания. Рисование происходит с помощью алгоритма Брезенхема или его модификаций. Т.е. рассчитывается теоретический путь линии из точки (x0, y0) в точку (x1, y1) и, перо, пробегая по этому пути, закрашивает пиксели, в которых путь проходит больше некоей величины (в разных реализациях этого алгоритма используются разные метрики — угол прохождения, длина отрезка и т.д.)

В результате получается ступенчатая линия (aliased line или grained line). Интересно, что слово aliased в техническом словаре переводится как «с побочными эффектами», т.е. речь идет о зернистой линии (grained) или линии с изъянами.

Визуально эта линия выглядит грязно и неточно. Разумеется, если мы уменьшим размер пикселя, то необходимость в сглаживании отпадет сама собой, как это, например, происходит с печатными машинами. Уже на 300 dpi глаз не различает границ пикселей, поэтому на печатном листе вы не увидите ступенек, хотя они там, разумеется, присутствуют.

Но качество экранов еще не скоро дорастет до качества принтеров. Впрочем, в этом направлении сделаны большие сдвиги (привет Retina).

Вернемся к линиям. Для исправления этой ситуации придумано множество разных техник.

Одна из техник сглаживания при рисовании линий — алгоритм Ву. Как и для Брезенхема, рассчитывается теоретическая линия и для пикселей меняется яркость в зависимости от того, на каком расстоянии находится пиксель от линии. Получается, что «зубцы» никуда не исчезают, но их хуже видно. Линия более сглаженная.

Развитием этой техники стало субпиксельное сглаживание.
Дело в том, что на изменение цвета и на изменение яркости наше зрение реагирует по разному. Поэтому если просто изменить значение яркости пикселя, то получится, что он изменит и цвет. Это приводит с тому, что линии могут снова стать зубчатыми, но «зубчатость» проявляется в цвете граней и линии становятся неряшливыми. Для этого стали менять не только яркость пикселей, но и учитывать то, как глаза реагируют на цвета. При увеличении становится заметно, что линия, сглаженная субпиксельным сглаживанием (а это все шрифты в Windows, см. ClearType, в OS X, см. Quartz, в *nix, см. FreeType), по краям разноцветная.

И в основе лежит все тот же алгоритм Ву и его модификации.
Результат его работы показан на вложенной картинке.
Обратите внимание на левый нижний угол окна на картинке — там та же линия нарисована в реальном масштабе.

Есть еще полноэкранное сглаживание (в противовес сглаживанию примитивов), но это выходит за рамки настоящей работы.

Автор:  Димыч [ Среда, 29 Январь, 2014 16:37 ]
Заголовок сообщения:  Re: Anti-Grain для Ports

Пётр Кушнир писал(а):
А битмап у вас представлен в платформонезависимом виде или тоже в виде дескриптора (со скрытой структурой)?
Из библиотеки возвращаю указатель на структуру. Его можно воспринимать как дескриптор.
Внутри же битмап находится в платформонезависимом виде, в виде массива трехбайтных пикселей (BGR).
В принципе, если сильно надо будет, массив можно будет вытащить наружу. Но пока я не видел необходимости.

Страница 4 из 6 Часовой пояс: UTC + 3 часа
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/