LINUX.ORG.RU

Пишу новое меню для Xash3D FWGS

 ,


2

2
Пишу новое меню для Xash3D FWGS

Примерно полгода занимаюсь разработкой новой меню библиотеки для движка Xash3D FWGS. Причины того просты для любого, кто когда-либо читал исходный код старого меню — работать с ним возможно, но очень сложно. Растёт оно ещё из Quake II, где глубоко уважаемый Джон Кармак не тратил много времени на написание игровых меню, которое в свою очередь растёт из Quake I. И наверное правильно делал, тогда это банально не ценилось, вплоть до Doom III.

Изначально идея была в том, чтобы перенести код с чистого Си на С++, но как и бывает — многие моменты пришлось переосмыслить и внести нововведения. Вот о них я и постараюсь рассказать.

  • Добавлены ивенты, чтобы задавать действия разным контролам, вместо их обработки по захардкоженным ID, в которых можно ошибиться и вообще.
  • В старом меню никакой системы элементов-родителей. Всё было статично и захардкожено. Я внёс новый элемент управления, который может содержать в себе другие элементы управления. Развив эту мысль появилась даже очень упрощенная система окон. (в правом верхнем углу видно список текущих окон)
  • mittorn-ом был написан очень красивый прогресс подключения к серверу, который в свою очередь и является окном. Его можно увидеть в видео по ссылке ниже.
  • Каждое окно имеет возможность отрисовать свою анимацию. В главной ветке я реализовал плавной смены прозрачности между окнами для соответствия с анимацией старого Half-Life. Для демонстрации я писал такое
  • Старое меню использовало моноширинные шрифты родом из Quake III Arena. Я от них наконец полностью избавился, как и от кода а-ля
    width = charWidth * strlen( sz )
    , заменив собственным шрифторендером. Под Windows используются возможности GDI, для всех остальных есть FreeType2 и stb_truetype.h рендеры. Поддержка последнего была добавлена специально для мобильных устройств, дабы не тащить по зависимостям достаточно крупный FreeType2. ШГ осталось, но всё-таки меньше, чем было.
  • Из предыдущего пункта вытекает и этот. Ранее таблицы эмулировались кучей отступов из пробелов, а каждый пункт таблицы был всего-лишь очень длинной строкой. Поэтому я написал настоящие таблицы, которые могут отображать не только текст, но и картинки. В будущем хочу добавить фичу отрисовки даже контролов внутри ячеек. Собственно, это и на скрине.
  • Динамически построенные меню! На основе так называемых Script Config-ов строится вот меню конфигурации. Сами конфиги пишутся моддерами и вообще эта фича присутствует начиная с самых ранних версий GoldSource и есть даже в движке Source. Про Source 2 не знаю, игр на нём ещё нет(DotA2 за игру не считается). Пример.
  • Возможность настроить положение, стиль и ограниченно логику контролов через resource-файлы. Пример.
  • Так же в планах написать поддержку переводов, дабы не оставаться с текстом, как в скриншоте выше.

Поскольку я хочу, чтобы мой код попал не только в форк движка, но в оригинальный Xash3D, а его автор(Дядя Миша) требует возможность сборки с MSVC 6, я сделал опцию сборки с отключенным требованием С++11. Собрать его можно задефайнив макрос MY_COMPILER_SUCKS.

А при чём тут Linux? Меню написано для форка игрового движка, который почти 3 года как работает под Linux. А ещё под кучей других платформ, вроде Windows, Android, *BSD, OSX, iOS. Недавно благодаря тому же mittorn появилась даже поддержка запуска сервера под Big Endian платформами и улучшена поддержка 64-битных ОС.

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

>>> Просмотр (1920x1080, 895 Kb)

★★★★★

Проверено: JB ()

Вот он - эталонный «Just For Fun». Школоте не понять :)

Porthos ★★★★ ()

Да, конечно удачи вам в хорошем начинании. И надеюсь у вас не получится объектно орентированного фреймворка или html5+css парсера, а будет просто лёгкое и понятное меню с настройками.

kirill_rrr ★★★★★ ()
Ответ на: комментарий от kirill_rrr

Задача в том, чтобы не вылезти за пределы 1 МБ в сумме: xash.dll + menu.dll + hl.exe.

Хоть и для форка движка это не имеет большое значение, но имеет для автора оригинального движка. Поэтому ни о какой жирноте речи не идёт.

a1batross ★★★★★ ()

я сделал опцию сборки с отключенным требованием С++11. Собрать его можно задефайнив макрос MY_COMPILER_SUCKS

Хороооош ))

ecko ★★★★ ()

Фи, плюсятина - такие вещи нужно на си делать с=

Движок то сишный.

SL_RU ★★ ()
Ответ на: комментарий от SL_RU

А движку в принципе почти не нужно ООП представление, иначе это лишь раздует код на ровном месте.

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

a1batross ★★★★★ ()
Ответ на: комментарий от thunar

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

a1batross ★★★★★ ()

Как же мне жаль создателей своих GUI... Ибо велосипеды на каждом шагу. Все, почему-то забывают, что самая сложная часть GUI - отрисовка текста. Никто её нормально не умеет.

PS: почему не imgui, cegui и тонна подобных?

PSS: если не ошибаюсь, в Dear Esther меню на Qt =)

RazrFalcon ★★★ ()
Ответ на: комментарий от RazrFalcon

Написание своих GUI очень полезно в плане получения опыта, да и вообще становится понятнее как работает большинство графических тулкитов.

PS: почему не imgui, cegui и тонна подобных?

А эта тонна подобных умеет в нормальную кросс-платформу (Android, iOS), может собираться MSVC 6 и укладывается в 1 МБ?

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

EXL ★★★★★ ()
Последнее исправление: EXL (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Никто её нормально не умеет.

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

PS: почему не imgui, cegui и тонна подобных?

1) Я пишу тот минимум, что мне нужен. Может сверх, если это мне просто интересно, но пригодится потом.

2) Под них надо менять MenuAPI для нормальной отрисовки, ибо в присутствии одни лишь прямоугольники. А второму вообще нужен OpenGL 2.x. Когда-нибудь в движке будут рендеры в отдельных либах и можно будет хоть написать Vulkan рендер...

PSS: если не ошибаюсь, в Dear Esther меню на Qt =)

А я не удивлён. Зная Source, там такое возможно. Но непонятно зачем, ибо там есть очень фичастый и удобный VGUI2. Кое-где я им вдохновлялся.

a1batross ★★★★★ ()
Последнее исправление: a1batross (всего исправлений: 2)
Ответ на: комментарий от RazrFalcon

PSS: если не ошибаюсь, в Dear Esther меню на Qt =)

Посмотрел, ничего похожего на Qt не нашёл ни в Dear Esther, ни в Dear Esther, ни в Dear Esther: Landmark Edition.

Почему у вас возникло такое предположение?

EXL ★★★★★ ()
Ответ на: комментарий от a1batross

Зная Source, там такое возможно. Но непонятно зачем, ибо там есть очень фичастый и удобный VGUI2.

Судя по всему, они ушли с Source. На Unity 5 =)

EXL ★★★★★ ()
Ответ на: комментарий от EXL

Почему у вас возникло такое предположение?

Наверное все эти VGUI2 контролы напоминают какой-нибудь GUI тулкит. И почему-то именно Qt. O_o

Хотя VGUI2 что только не пользуется. И HLDS/SourceDS морды, и вроде даже Steam в ПК версии, но это неточно.

Судя по всему, они ушли с Source. На Unity 5 =)

Да и там дефолтный GUI вполне человечный. И опять же — свой, самописный.

a1batross ★★★★★ ()
Ответ на: комментарий от a1batross

Наверное все эти VGUI2 контролы напоминают какой-нибудь GUI тулкит. И почему-то именно Qt. O_o

Я точно помню, что какая-то игра использовала QtQuick/QML для GUI. Ну или пробовала использовать. На ЛОРе кстати вроде проскакивала эта инфа. Но это явно не Dear Esther, а что-то другое.

EXL ★★★★★ ()
Ответ на: комментарий от EXL

А вообще, почему бы и нет? Всяко лучше, чем пихать в игру GUI на уёб-технологиях, как устаревших(да, я про тебя CS:GO с гуём на Flash), так и современных, это вообще не должно существовать.

a1batross ★★★★★ ()
Ответ на: комментарий от a1batross

Меню как в Doom I сложно будет сделать?

ДМ писал, что ты для QR меню сделал, где его можно посмотреть?

Когда-нибудь в движке будут рендеры в отдельных либах и можно будет хоть написать Vulkan рендер...

Vulkan было бы интересно.

Cybermax ()

Под Windows используются возможности GDI, для всех остальных есть FreeType2 и stb_truetype.h рендеры.

Почему не что-либо одно?

Есть ли сравнения по скорости рендеринга между freetype2 и stb?

andreyu ★★★★★ ()

дабы не тащить по зависимостям достаточно крупный FreeType2.

На самом деле нужно не так много файлов для рендеринга:


src/autofit/autofit.c \
src/base/basepic.c \
src/base/ftapi.c \
src/base/ftbase.c \
src/base/ftbbox.c \
src/base/ftbitmap.c \
src/base/ftdbgmem.c \
src/base/ftdebug.c \
src/base/ftglyph.c \
src/base/ftinit.c \
src/base/ftpic.c \
src/base/ftstroke.c \
src/base/ftsynth.c \
src/base/ftsystem.c \
src/cff/cff.c \
src/pshinter/pshinter.c \
src/psnames/psnames.c \
src/raster/raster.c \
src/sfnt/sfnt.c \
src/smooth/smooth.c \
src/truetype/truetype.c \

andreyu ★★★★★ ()
Ответ на: комментарий от RazrFalcon

почему не imgui,

Потому, что imgui для рендеринга фонта использует stb_truetype.
И, мягко говоря, плохо кастомизируется в плане тем.

andreyu ★★★★★ ()
Ответ на: комментарий от EXL

А эта тонна подобных умеет в нормальную кросс-платформу (Android, iOS), может собираться MSVC 6 и укладывается в 1 МБ?

За остальные не скажу, а imgui умеет. Там вообще запрещено все, что >= c++11 (мой патч зарезали из-за этого - https://github.com/ocornut/imgui/pull/1347 ). А вообще imgui требует серьезной доработки и рефакторинга. Но очень хорошо подходит в качестве gui для встроенного в движок отладчика.

andreyu ★★★★★ ()
Ответ на: комментарий от a1batross

Пока не вижу, что ещё с выводом текста надо сделать

Ну если вам хватает - то ок. Я про работу с текстом целиком, ака: bidi, cjk, align, word wrap, hyphenation, системные/нативные шрифты и стили, разные типы шрифтов (а не только ttf), лигатуры и прочий ад.

RazrFalcon ★★★ ()
Ответ на: комментарий от Cybermax

Нет, не сложно. Но время надо потратить. :)

ДМ писал, что ты для QR меню сделал, где его можно посмотреть?

В сорцах QR? Там ничего интересного, просто порт menu.c из Quake I.

a1batross ★★★★★ ()
Ответ на: комментарий от andreyu

Под Windows банально не хочется завязываться на чем-то, если это все равно предоставляет система.

А так stbtt я не учитывал изначально, да и результат ft2 на глаз куда приятнее, особенно на низких разрешениях. Сразу видно что из них умеет хинтинг. Может стоит попробовать им под Android воспользоваться.

Время рендеринга выводится в консоль. stbtt почти в джва раза быстрее, но это на моём ПК. На Android ft2 небось будет шуршать несколько секунд. Как проверю, отпишусь с результатами.

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

a1batross ★★★★★ ()
Ответ на: комментарий от RazrFalcon

bidi

cjk

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

align

word wrap

системные/нативные шрифты и стили

Есть. Движок ни один внешний шрифт не требует.

hyphenation

разные типы шрифтов (а не только ttf)

лигатура

прочий ад

Банально не нужно в текущих задачах.

a1batross ★★★★★ ()
Ответ на: комментарий от a1batross

Под Windows банально не хочется завязываться на чем-то, если это все равно предоставляет система.

Не проще ли поддерживать одну реализацию и не городить абстракцию ради поддержки разных реализаций?

А так stbtt я не учитывал изначально, да и результат ft2 на глаз куда приятнее, особенно на низких разрешениях.

Ну да, об это написано в stb_truetype. Там есть несколько реализаций рендерера - одна быстрее, но менее качественная, вторая медленнее на 15%, но качественнее.

На Android ft2 небось будет шуршать несколько секунд.

Я в рантайме рендерю глиф и пакую его на текстуру, тормозов не вижу.

Как проверю, отпишусь с результатами.

Ага, было бы интересно. Но по моим прикидкам freetype2 должен быть быстрее, чем stb_truetype.

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

Да, это удобно. Я использую для этого imgui.

andreyu ★★★★★ ()
Ответ на: комментарий от andreyu

Не проще ли поддерживать одну реализацию и не городить абстракцию ради поддержки разных реализаций?

Почти не затратил сил на gdi реализацию, поскольку её писал не я. А поддерживать одновременно ft2 и stbtt не составляет труда.

Я в рантайме рендерю глиф и пакую его на текстуру, тормозов не вижу.

Ну это норм. Я когда делал, предполагал, чтобы на протяжении работы как можно меньше дёргалась библиотека. Впрочем, дёргать её приходится только из-за получения метрик, а они сразу пихаются в кеш. Необходимые глифы сразу при старте отрисовываются в атлас. У меня SubImage нет, поэтому подрисовать глиф когда он понадобится я не могу, но когда попадёт в движок — исправлю этот досадный недостаток.

Ещё раз замерил скорость ft2 и stbtt. Возможно, я в прошлый раз неправильно посчитал, ошибся или что-то ещё, но сейчас выиграл по скорости ft2. Несколько замеров провёл, в среднем ft2 на 0.05-0.1 долей секунды быстрее. В процентном соотношении получается, что ft2 быстрее на 20-30%.

Да, это удобно. Я использую для этого imgui.

Мне бы это ещё написать. В планах пока профайлер.

a1batross ★★★★★ ()
Ответ на: комментарий от a1batross

Почти не затратил сил на gdi реализацию, поскольку её писал не я. А поддерживать одновременно ft2 и stbtt не составляет труда.

Только непонятно зачем это нужно? Что freetype2, что stb_truetype работают на всех платформах. Зачем нужно использовать разные реализации?

У меня SubImage нет, поэтому подрисовать глиф когда он понадобится я не могу, но когда попадёт в движок — исправлю этот досадный недостаток.

Я это делаю без subimage. А если для очередного глифа нет места, то меняю размер атласа.

В процентном соотношении получается, что ft2 быстрее на 20-30%.

Я сам замеров не делал, но встречал в сети разницу в три раза, в пользу freetype2. Возможно stb_truetype просто хорошо оптимизировали. Значит можно рассмотреть переход на него.

Мне бы это ещё написать.

Было бы желание :)

В планах пока профайлер.

Свой профайлер?

andreyu ★★★★★ ()
Ответ на: комментарий от andreyu

Только непонятно зачем это нужно? Что freetype2, что stb_truetype работают на всех платформах. Зачем нужно использовать разные реализации?

Всё это пока эксперимент. Перезапустив тесты на скорость, ft2 показал себя очень даже лучше. Может в релизе только он и будет. Учитывая, что он наиболее прилично выглядит на низких разрешениях, то это вообще.

Я это делаю без subimage. А если для очередного глифа нет места, то меняю размер атласа.

Мне показалось, что создавать новую страницу 512x512 немного быстрее в случае нехватки. Дорисовка по требованию как раз заполнит незанятое место, когда дорисовка будет реализована. Во всяком случае, задел под неё оставлен.

Было бы желание :)

И свободное время же.

Свой профайлер?

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

a1batross ★★★★★ ()
Ответ на: комментарий от a1batross

Учитывая, что он наиболее прилично выглядит на низких разрешениях, то это вообще.

Чую придется мне самому сделать сравнения качества и замеры производительности. Возможно у меня узкое место не рендеринг глифа, а их упаковка в атлас или поиск нужного глифа на атласе.

Мне показалось, что создавать новую страницу 512x512 немного быстрее в случае нехватки.

Новый атлас - это шанс нарваться на лишнее переключение текстуры при отрисовке строки. Запросто может случиться так, что текстуры будут переключаться по несколько раз на одну строку. Что само по себе печально.

Дорисовка по требованию как раз заполнит незанятое место, когда дорисовка будет реализована. Во всяком случае, задел под неё оставлен.

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

По подсистемам движка.

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

andreyu ★★★★★ ()
Ответ на: комментарий от andreyu

Возможно у меня узкое место не рендеринг глифа, а их упаковка в атлас или поиск нужного глифа на атласе.

У меня они распиханы в rbtree. Получилось достаточно быстро, как в добавлении, так и в поиске.

Новый атлас - это шанс нарваться на лишнее переключение текстуры при отрисовке строки. Запросто может случиться так, что текстуры будут переключаться по несколько раз на одну строку. Что само по себе печально.

Кстати, верно. На крупный текст выделяется штуки 4-5 таких листов. Нарваться на переключение легко.

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

Надо еще подумать о том, как писать глифы оптимально в высоту, ибо сейчас они записаны с одинаковым пустым местом между строками.

a1batross ★★★★★ ()
Последнее исправление: a1batross (всего исправлений: 1)
Ответ на: комментарий от a1batross

У меня они распиханы в rbtree. Получилось достаточно быстро, как в добавлении, так и в поиске.

Я о способе упаковки глифов на текстуре. В рантайме я использую построчное хранение - это относительно быстро и относительно компактно. А в офлайновой утилите есть два варианта - медленный и kd-tree: https://bitbucket.org/andreyu/texture-packer

Нарваться на переключение легко.

Все может быть гораздо хуже: строка «ababababab..abab», один глиф на одной текстуре, второй на другой. Наверное можно придумать хитрожелтый батчинг, когда строка отрисуется за два дипа вместо сотни дипов, но это лишний геморрой.

Достаточно будет только высоту увеличить.

Я делаю так:
if (w <= h) { w <<= 1; } else { h <<= 1; }

Надо еще подумать о том, как писать глифы оптимально в высоту, ибо сейчас они записаны с одинаковым пустым местом между строками.

У меня хранится только видимая часть глифа + смещение глифа.

andreyu ★★★★★ ()
Ответ на: комментарий от andreyu

А, ну так я упаковываю точно так же.

if (w <= h) { w <<= 1; } else { h <<= 1; }


Я наверное что-то не понимаю, пока пытаюсь прокручивать сиё в голове. Это ж получается, что увеличивая его в ширину предыдущий буфер не получится просто скопировать как есть, его нужно построчно копировать. Не то чтобы это сложно или сильно медленнее, просто больше.

a1batross ★★★★★ ()
Последнее исправление: a1batross (всего исправлений: 2)
Ответ на: комментарий от a1batross

Это ж получается, что увеличивая его в ширину предыдущий буфер не получится просто скопировать как есть, его нужно построчно копировать.

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

andreyu ★★★★★ ()

ТС, а сколько лет ты занимаешься доработкой Xash3D?

За какое время овладел Си/С++?

А вообще рад за соплеменника (за своего), хоть кто-то из казахов умеет в программирование. Я вот смог только в Python и JS. Си еще только начал изучать.

RedEyedMan4 ★★★★★ ()
Последнее исправление: RedEyedMan4 (всего исправлений: 1)
Ответ на: комментарий от RedEyedMan4

С конца 2014-ого где-то. Потому что первый релиз уже был 1 апреля 2015-ого.

С++ я до сих пор не владею достаточно, особенно с последними стандартами, хотя пишу года 4. Сишку же начал учить как стал работать над движком.

Спасибо, конечно.

a1batross ★★★★★ ()
Ответ на: комментарий от awesomenickname

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

Firefox стал разочаровывать, а Chrome... ну он хром.

Хотел ещё оперу старую скомпилять, благо сорцы слили. Но руки так и не дошли.

a1batross ★★★★★ ()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)