diff --git a/CHANGELOG.md b/CHANGELOG.md index 2db70633..845cedc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,138 +1,96 @@ -# 0.24 - 2024.11.07 +# 0.25 - 2024.12.01 -[Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.24/doc/en/main-page.md) for 0.24 +[Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/tree/release-0.25/doc/en/main-page.md) for 0.25 Table of contents: - [Added](#added) - [Functions](#functions) -- [Changes](#changes) - [Fixes](#fixes) ## Added -- particles -- VEC3 models support -- handhold item display -- rules -- events: - - on_block_broken (documented) - - on_block_placed (documented) - - on_block_interact +- 3dtext +- blockwraps +- network (http requests and sockets) - libraries: - - gfx.particles - - utf8 - - rules -- bindings: - - player.destroy - - player.fast_interaction -- water overlay -- block models from OBJ or VEC3 -- bicubic heightmaps interpolation method -- unicode escapes support -- fragments placements -- console commands: - - time.daycycle - - fragment.place - - rule.list - - rule.set -- text field 'subconsumer' -- shader uniforms: - - u_lightDir to main shader - - u_dayTime to skybox shader -- block properties: - - overlay-texture - - model-name -- item properties: - - model-name -- 'Open content folder' buttons -- 'Background framerate limit' setting + - base64 + - gfx.text3d + - gfx.blockwraps + - network +- events: + - on_replaced + - on_block_replaced + - on_player_tick +- structures 'lowering' property +- add 'hint' property to textbox +- add 'taking' and 'placing' properties to slot and slotsgrid +- add 'scroll-step' property to container +- add 'line-numbers' and 'text-color' to textbox +- modules: + - base:util +- uinode property 'id' +- block.materials table +- block.properties table +- item.properties table +- add version to world info table +- add 'sizeSpread' particles property +- add user properties ### Functions -- core.open_folder -- world.get_generator -- world.is_open -- item.placing_block -- item.model_name -- item.emission -- entities.get_hitbox -- utf8.tobytes -- utf8.tostring -- utf8.length -- utf8.codepoint -- utf8.encode -- utf8.sub -- utf8.upper -- utf8.lower -- file.read_combined_object -- fragment:place -- rules.create -- rules.listen -- rules.unlisten -- rules.get -- rules.set -- rules.reset -- input.set_enabled -- hud._is_content_access -- hud._set_content_access -- hud._set_debug_cheats -- gfx.particles.emit -- gfx.particles.stop -- gfx.particles.get_origin -- gfx.particles.set_origin -- assets.load_texture - -Documented: -- file.read_combined_list -- file.list -- file.list_all_res -- input.is_active -- table.copy -- table.count_pairs -- table.random -- table.has -- table.index -- table.remove_value -- table.tostring -- string.explode -- string.split -- string.pattern_safe -- string.formatted_time -- string.replace -- string.trim -- string.trim_left -- string.trim_right -- string.starts_with -- string.ends_with -- math.clamp -- math.rand -- is_array -- parse_path -- timeit -- sleep - -## Changes - -- major skybox optimization -- chunks-renderer optimization -- libspng replaced with libpng on Windows -- console commands: - - blocks.fill - - fragment.save -- added 'def' to core.get_setting_info tables -- water texture +- player.is_infinite_items +- player.set_infinite_items +- player.is_instant_destruction +- player.set_instant_destruction +- player.get_name +- player.set_name +- hud.open +- base64.encode +- base64.decode +- utf8.escape +- string.escape +- textbox:lineAt +- textbox:linePos +- network.get +- network.get_binary +- network.tcp_connect +- network.tcp_open +- network.get_total_upload +- network.get_total_download +- gfx.text3d.show +- gfx.text3d.hide +- gfx.text3d.get_text +- gfx.text3d.set_text +- gfx.text3d.get_pos +- gfx.text3d.set_pos +- gfx.text3d.get_axis_x +- gfx.text3d.set_axis_x +- gfx.text3d.get_axis_y +- gfx.text3d.set_axis_y +- gfx.text3d.set_rotation +- gfx.text3d.update_settings ## Fixes -- [fix fatal error on editing texbox not having any consumer](https://github.com/MihailRis/VoxelEngine-Cpp/commit/22fa082fc6299ffa3196d62c67e01b849c35b8eb) -- [fix commands boolean type support](https://github.com/MihailRis/VoxelEngine-Cpp/commit/a50cb109c8e3ca0f7a591bf126f07aee36c962e6) -- [fix potential null dereferences on incorrect block.* functions use](https://github.com/MihailRis/VoxelEngine-Cpp/commit/961773c9f9745c15eb8d697c1538ac8e21f24da3) -- [fix: draw-group not copied](https://github.com/MihailRis/VoxelEngine-Cpp/commit/dc8bad2af67e70b0b2346f516028e5795f597737) -- [fix: generator-providing pack may be removed](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6f2f365278eb1866c773890471b7269a5ef45305) -- [fix colision check on block place](https://github.com/MihailRis/VoxelEngine-Cpp/commit/726ee8ad703bc57530b881450b8839aaec6b97c9) -- [fix collision detection bug](https://github.com/MihailRis/VoxelEngine-Cpp/commit/7fcc34ba4cf14097dfda26054b028c5e8771d26c) -- [fix: blocks lighting bug fix](https://github.com/MihailRis/VoxelEngine-Cpp/commit/9d3e872f88de2648f8c0f2e4611b30f5ce8999cf) -- [fix: inaccurate framerate limit on Windows](https://github.com/MihailRis/VoxelEngine-Cpp/commit/3f531bbf98da5ad751dce1220c5c5fdf35f86c92) -- [fix block.get_hitbox again](https://github.com/MihailRis/VoxelEngine-Cpp/commit/edad594101e5808ccf14e0edefedbe87cb8f983b) -- [fix string.replace](https://github.com/MihailRis/VoxelEngine-Cpp/commit/44fd5416a9a110a12f8b3f2d369e5638055b306e) +- [fix translucent blocks render](https://github.com/MihailRis/VoxelEngine-Cpp/pull/370) +- [fix blocks selection with semi-transparent blocks](https://github.com/MihailRis/VoxelEngine-Cpp/commit/171cbb48d099032d7e78c51a46c374104f96f0d1) +- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b) +- [mip-mapping related fixes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/d9277e1b31714632bd7f5f601b8362a9e7cb8819) +- [fix disabled slots display](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e8ee3e04b1398a3ada8445591267525304410571) +- [fix attack](https://github.com/MihailRis/VoxelEngine-Cpp/commit/bc17abc8b3ee7ff9027f7e3c375ca0330bb8e7bc) +- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b) +- [fix stdlib.lua](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6ec33ab98c78523eaececf40f113f2323d25a33a) +- [fix file.write_bytes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/0fec17a8b69ac81255b77022f3af5addf8fcc8f8) +- [fix World::nextInventoryId](https://github.com/MihailRis/VoxelEngine-Cpp/commit/371fdaedcef2c163edd226160f388068b2bf5e83) +- [fix block inventory unbinding](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6f6c2a916afd6b9b79221111fc72b1a86109be13) +- [fix xml text escapes handling](https://github.com/MihailRis/VoxelEngine-Cpp/commit/53c54dc91d132c221ff5fea2f7e9fb4568db9a0f) +- [fix `\'` escape parsing](https://github.com/MihailRis/VoxelEngine-Cpp/commit/2bc6cbda2e809b14fa6cffe09161b53c1636675f) +- [fix crosshair look](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e034bda477c35efe96548e78ecc722966a7a2197) +- [fix: actual block inventory size not updating on inventory-size property update](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1ba5b0ce33103e539ccb199ee1cd52095e286a1f) +- [fix falling block hitbox](https://github.com/MihailRis/VoxelEngine-Cpp/commit/352ef6485a4b796d1cdc8dd0e00ab1a1d72a2c0a) +- [fix console position](https://github.com/MihailRis/VoxelEngine-Cpp/commit/3ea213e8d3cee7be55ec39ffb18dc557dec7557b) +- [fix: fatal error on pack removal when no world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/78d5ab02c2ba8a3d05cf5639eb10a49c9ca14ec3) +- [fix custom model lighting](https://github.com/MihailRis/VoxelEngine-Cpp/commit/a333cadfcaeb485a30833343d55faf01b28a5c5f) +- [fix: emitter does not skip particles](https://github.com/MihailRis/VoxelEngine-Cpp/commit/983e516fb4ebc1f2def592f2b7f3195d968deed2) +- [fix old custom models render](https://github.com/MihailRis/VoxelEngine-Cpp/commit/82733d38011b52a426cb74560521949c1cd43cc1) diff --git a/CMakeLists.txt b/CMakeLists.txt index f465fcb3..a56457bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,4 +81,4 @@ file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/res DESTINATION ${CMAKE_CURRENT_BINARY_DIR if (VOXELENGINE_BUILD_TESTS) enable_testing() add_subdirectory(test) -endif() +endif() \ No newline at end of file diff --git a/README.md b/README.md index 0b586d95..418d372c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Latest release - [Download](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) -- [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/ru/main-page.md) +- [Documentation](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/en/main-page.md) | [Документация](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/ru/main-page.md) ## Build project in Linux @@ -62,6 +62,12 @@ If you use Wayland sudo pacman -S glfw-wayland glew glm libpng libvorbis openal luajit libcurl ``` +And you need entt. In yay you can use + +```sh +yay -S entt +``` + ### Build engine with CMake ```sh diff --git a/doc/en/main-page.md b/doc/en/main-page.md index 4d487f5a..0daa4729 100644 --- a/doc/en/main-page.md +++ b/doc/en/main-page.md @@ -1,8 +1,8 @@ # Documentation -Documentation for the engine of in-development version 0.25. +Documentation for in-development version 0.26. -[Documentation for stable release 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/en/main-page.md) +[Documentation for stable release 0.25.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/en/main-page.md) ## Sections @@ -14,9 +14,10 @@ Documentation for the engine of in-development version 0.25. - [Content-packs](content-packs.md) - [Engine usage recommendations](engine-use-recommendations.md) - [Item properties](item-properties.md) +- [Particles](particles.md) - [Resources (resources.json)](resources.md) - [Rigging](rigging.md) - [Scripting](scripting.md) +- [Text styles](text-styles.md) - [World generator engine](world-generator.md) - [XML UI building](xml-ui-layouts.md) -- [Particles](particles.md) diff --git a/doc/en/scripting/builtins/libgui.md b/doc/en/scripting/builtins/libgui.md index 5ec2490f..3132bce3 100644 --- a/doc/en/scripting/builtins/libgui.md +++ b/doc/en/scripting/builtins/libgui.md @@ -39,3 +39,25 @@ gui.get_locales_info() -> table of tables { ``` Returns information about all loaded locales (res/texts/\*). + +```lua +gui.clear_markup( + -- markup language ("md" - Markdown) + language: str, + -- text with markup + text: str +) -> str +``` + +Removes markup from text. + +```lua +gui.escape_markup( + -- markup language ("md" - Markdown) + language: str, + -- text with markup + text: str +) -> str +``` + +Escapes markup in text. diff --git a/doc/en/scripting/builtins/libnetwork.md b/doc/en/scripting/builtins/libnetwork.md index 1e519d9d..48caefbd 100644 --- a/doc/en/scripting/builtins/libnetwork.md +++ b/doc/en/scripting/builtins/libnetwork.md @@ -39,7 +39,7 @@ The Socket class has the following methods: ```lua -- Sends a byte array -socket:send(table|ByteArray) +socket:send(table|ByteArray|str) -- Reads the received data socket:recv( @@ -59,6 +59,9 @@ socket:is_alive() --> bool -- Checks if the connection is present (using socket:send(...) is available). socket:is_connected() --> bool + +-- Returns the address and port of the connection. +socket:get_address() --> str, int ``` ```lua @@ -80,6 +83,9 @@ server:close() -- Checks if the TCP server exists and is open. server:is_open() --> bool + +-- Returns the server port. +server:get_port() --> int ``` ## Analytics diff --git a/doc/en/scripting/events.md b/doc/en/scripting/events.md index 4b13ec7b..cc820898 100644 --- a/doc/en/scripting/events.md +++ b/doc/en/scripting/events.md @@ -108,6 +108,12 @@ function on_block_placed(blockid, x, y, z, playerid) Called on block placed by player +```lua +function on_block_replaced(blockid, x, y, z, playerid) +``` + +Called on block replaced with other by player + ```lua function on_block_broken(blockid, x, y, z, playerid) ``` diff --git a/doc/en/scripting/ui.md b/doc/en/scripting/ui.md index 4f132462..c990a197 100644 --- a/doc/en/scripting/ui.md +++ b/doc/en/scripting/ui.md @@ -32,7 +32,7 @@ document["worlds-panel"]:clear() Properties that apply to all elements: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | ------------- | ------ | ---- | ----- | ------------------------------------------- | | id | string | yes | *no* | element id | | pos | vec2 | yes | yes | element position inside a container | @@ -60,17 +60,17 @@ Common element methods: Common methods for containers (elements: container, panel, button, pagebox): -| Method | Description | -| ------------------------------- | ------------------------------------------------------------------ | -| clear() | clears content | -| add(xml) | adds an element, creating it using xml code. Example: `container:add("")` | -| setInterval(interval, callback) | assigns a function to be executed repeatedly at an interval specified in milliseconds | +| Method | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------- | +| clear() | clears content | +| add(xml) | adds an element, creating it using xml code. Example: `container:add("")` | +| setInterval(interval, callback) | assigns a function to be executed repeatedly at an interval specified in milliseconds | ## Textbox Properties: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | ----------- | ------ | ---- | ----- | ------------------------------------------------------------------------------------ | | text | string | yes | yes | entered text or placeholder | | placeholder | string | yes | yes | placeholder (used if nothing has been entered) | @@ -82,6 +82,8 @@ Properties: | textWrap | bool | yes | yes | automatic text wrapping (only with multiline: "true") | | valid | bool | yes | no | is the entered text correct | | textColor | vec4 | yes | yes | text color | +| syntax | string | yes | yes | syntax highlighting ("lua" - Lua) | +| markup | string | yes | yes | text markup language ("md" - Markdown) | Methods: @@ -95,7 +97,7 @@ Methods: Properties: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | ---------- | ----- | ---- | ----- | --------------------- | | value | float | yes | yes | current value | | min | float | yes | yes | minimum value | @@ -108,7 +110,7 @@ Properties: Properties: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | ----- | ------ | ---- | ----- | ------------ | | page | string | yes | yes | current page | @@ -123,7 +125,7 @@ Methods: Properties: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | ------- | ---- | ---- | ----- | ----------- | | checked | bool | yes | yes | mark status | @@ -131,7 +133,7 @@ Properties: Properties: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | ----- | ------ | ---- | ----- | ------------ | | text | string | yes | yes | button text | @@ -139,15 +141,16 @@ Properties: Properties: -| Title | Type | Read | Write | Description | -| ----- | ------ | ---- | ----- | ----------- | -| text | string | yes | yes | label text | +| Name | Type | Read | Write | Description | +| ------ | ------ | ---- | ----- | -------------------------------------- | +| text | string | yes | yes | label text | +| markup | string | yes | yes | text markup language ("md" - Markdown) | ## Image Properties: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | ----- | ------ | ---- | ----- | ------------ | | src | string | yes | yes | texture name | @@ -155,6 +158,6 @@ Properties: Properties: -| Title | Type | Read | Write | Description | +| Name | Type | Read | Write | Description | | --------- | ---- | ---- | ----- | ------------------------------------------------- | | inventory | int | yes | yes | id of the inventory to which the element is bound | diff --git a/doc/en/text-styles.md b/doc/en/text-styles.md new file mode 100644 index 00000000..e85437e1 --- /dev/null +++ b/doc/en/text-styles.md @@ -0,0 +1,21 @@ +# Text styles + +A proprietary Markdown dialect is used to mark up text styles. +Formatting works on UI elements: label and textbox, if `markup="md"` is explicitly specified. + +## Styles + +| Style | Example | Output | +| ------------- | ------------------------ | -------------------------- | +| Bold | `**Bold font**` | **Bold font** | +| Italic | `*Text in italics*` | *Text in italics* | +| Underline | `__Underlined text__` | Underlined text | +| Strikethrough | `~~Strikethrough text~~` | ~~Strikethrough text~~ | + +Styles can be combined. Example: +```md +***__Message__*** using *~~combed~~ combined* styles__~~.~~__ +``` +Output: + +***Message*** using *~~combed~~ combined* styles~~.~~ diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md index d77a93ed..e7008682 100644 --- a/doc/en/xml-ui-layouts.md +++ b/doc/en/xml-ui-layouts.md @@ -87,6 +87,7 @@ Inner text is a button text. - `autoresize` - automatic change of element size (default - false). Does not affect font size. - `multiline` - allows display of multiline text. - `text-wrap` - allows automatic text wrapping (works only with multiline: "true"). +- `markup` - text markup language ("md" - Markdown). ## *image* @@ -112,6 +113,8 @@ Inner text - initially entered text - `validator` - lua function that checks text for correctness. Takes a string as input, returns true if the text is correct. - `onup` - lua function called when the up arrow is pressed. - `ondown` - lua function called when the down arrow is pressed. +- `syntax` - syntax highlighting ("lua" - Lua). +- `markup` - text markup language ("md" - Markdown). ## *trackbar* diff --git a/doc/ru/main-page.md b/doc/ru/main-page.md index 800415c6..10dff292 100644 --- a/doc/ru/main-page.md +++ b/doc/ru/main-page.md @@ -1,8 +1,8 @@ # Документация -Документация движка разрабатываемой версии 0.25. +Документация разрабатываемой версии 0.26. -[Документация стабильной версии 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/ru/main-page.md) +[Документация стабильной версии 0.25.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.25/doc/ru/main-page.md) ## Разделы @@ -19,4 +19,5 @@ - [Свойства блоков](block-properties.md) - [Свойства предметов](item-properties.md) - [Скриптинг](scripting.md) +- [Стили текста](text-styles.md) - [Частицы](particles.md) diff --git a/doc/ru/scripting/builtins/libgui.md b/doc/ru/scripting/builtins/libgui.md index eb81cd5f..11dfde03 100644 --- a/doc/ru/scripting/builtins/libgui.md +++ b/doc/ru/scripting/builtins/libgui.md @@ -36,3 +36,25 @@ gui.get_locales_info() -> таблица таблиц где ``` Возвращает информацию о всех загруженных локалях (res/texts/\*). + +```lua +gui.clear_markup( + -- язык разметки ("md" - Markdown) + language: str, + -- текст с разметкой + text: str +) -> str +``` + +Удаляет разметку из текста. + +```lua +gui.escape_markup( + -- язык разметки ("md" - Markdown) + language: str, + -- текст с разметкой + text: str +) -> str +``` + +Экранирует разметку в тексте. diff --git a/doc/ru/scripting/builtins/libnetwork.md b/doc/ru/scripting/builtins/libnetwork.md index 8a937330..7fedf2bd 100644 --- a/doc/ru/scripting/builtins/libnetwork.md +++ b/doc/ru/scripting/builtins/libnetwork.md @@ -39,7 +39,7 @@ network.tcp_connect( ```lua -- Отправляет массив байт -socket:send(table|ByteArray) +socket:send(table|ByteArray|str) -- Читает полученные данные socket:recv( @@ -59,6 +59,9 @@ socket:is_alive() --> bool -- Проверяет наличие соединения (доступно использование socket:send(...)). socket:is_connected() --> bool + +-- Возвращает адрес и порт соединения. +socket:get_address() --> str, int ``` ```lua @@ -80,6 +83,9 @@ server:close() -- Проверяет, существует и открыт ли TCP сервер. server:is_open() --> bool + +-- Возвращает порт сервера. +server:get_port() --> int ``` ## Аналитика diff --git a/doc/ru/scripting/events.md b/doc/ru/scripting/events.md index 08192cfa..a5cc3e72 100644 --- a/doc/ru/scripting/events.md +++ b/doc/ru/scripting/events.md @@ -108,6 +108,12 @@ function on_block_placed(blockid, x, y, z, playerid) Вызывается после установки блока игроком +```lua +function on_block_replaced(blockid, x, y, z, playerid) +``` + +Вызывается после замены блока игроком + ```lua function on_block_broken(blockid, x, y, z, playerid) ``` diff --git a/doc/ru/scripting/extensions.md b/doc/ru/scripting/extensions.md index d4502f64..d0ddd365 100644 --- a/doc/ru/scripting/extensions.md +++ b/doc/ru/scripting/extensions.md @@ -10,6 +10,12 @@ table.copy(t: table) -> table Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной. +```lua +table.deep_copy(t: table) -> table +``` + +Функция глубокого копирования создает полную копию исходной таблицы, включая все её вложенные таблицы. + ```lua table.count_pairs(t: table) -> integer ``` diff --git a/doc/ru/scripting/modules/core_bit_converter.md b/doc/ru/scripting/modules/core_bit_converter.md index f9930560..44b915c7 100644 --- a/doc/ru/scripting/modules/core_bit_converter.md +++ b/doc/ru/scripting/modules/core_bit_converter.md @@ -1,93 +1,98 @@ # Модуль core:bit_converter +## Доступные порядки байтов +**LE (Little-Endian)** +**BE (Big-Endian)** +По умолчанию используется **LE** + ## Конвертация значений в байты и обратно ```lua -function bit_converter.string_to_bytes(string: str) -> table +function bit_converter.string_to_bytes(str: string) -> table ``` Конвертирует строку в байты ```lua -function bit_converter.bool_to_byte(boolean: bool) -> integer +function bit_converter.bool_to_byte(bool: boolean) -> integer ``` Конвертирует логический булев в байт ```lua -function bit_converter.single_to_bytes(number: single) -> table +function bit_converter.float32_to_bytes(float: number, [опционально] order: string) -> table ``` Конвертирует плавающее значение одинарной точности в байты ```lua -function bit_converter.double_to_bytes(number: double) -> table +function bit_converter.float64_to_bytes(float: number, [опционально] order: string) -> table ``` Конвертирует плавающее значение двойной точности в байты ```lua -function bit_converter.uint16_to_bytes(integer: int) -> table +function bit_converter.uint16_to_bytes(int: integer, [опционально] order: string) -> table ``` Конвертирует беззнаковое 2-х байтовое целое число в байты ```lua -function bit_converter.uint32_to_bytes(integer: int) -> table +function bit_converter.uint32_to_bytes(int: integer, [опционально] order: string) -> table ``` Конвертирует беззнаковое 4-х байтовое целое число в байты ```lua -function bit_converter.int16_to_bytes(integer: int) -> table +function bit_converter.sint16_to_bytes(int: integer, [опционально] order: string) -> table ``` Конвертирует знаковое 2-х байтовое целое число в байты ```lua -function bit_converter.int32_to_bytes(integer: int) -> table +function bit_converter.sint32_to_bytes(int: integer, [опционально] order: string) -> table ``` Конвертирует знаковое 4-х байтовое целое число в байты ```lua -function bit_converter.int64_to_bytes(integer: int) -> table +function bit_converter.int64_to_bytes(int: integer, [опционально] order: string) -> table ``` Конвертирует знаковое 8-и байтовое целое число в байты ```lua -function bit_converter.bytes_to_string(table: bytes) -> string +function bit_converter.bytes_to_string(bytes: table) -> string ``` Конвертирует массив байтов в строку ```lua -function bit_converter.byte_to_bool(integer: byte) -> boolean +function bit_converter.byte_to_bool(byte: integer) -> boolean ``` Конвертирует байт в логическое булевое значение ```lua -function bit_converter.bytes_to_single(table: bytes) -> number№ +function bit_converter.bytes_to_float32(bytes: table|Bytearray, [опционально] order: string) -> number ``` Конвертирует массив байтов в плавающее число одинарной точности ```lua -function bit_converter.bytes_to_double(table: bytes) -> number +function bit_converter.bytes_to_float64(bytes: table|Bytearray, [опционально] order: string) -> number ``` Конвертирует массив байтов в плавающее число двойной точности ```lua -function bit_converter.bytes_to_uint16(table: bytes) -> integer +function bit_converter.bytes_to_uint16(bytes: table|Bytearray, [опционально] order: string) -> integer ``` Конвертирует массив байтов в 2-х байтовое беззнаковое число ```lua -function bit_converter.bytes_to_uint32(table: bytes) -> integer +function bit_converter.bytes_to_uint32(bytes: table|Bytearray, [опционально] order: string) -> integer ``` Конвертирует массив байтов в 4-х байтовое беззнаковое число ```lua -function bit_converter.bytes_to_int16(table: bytes) -> integer +function bit_converter.bytes_to_sint16(bytes: table|Bytearray, [опционально] order: string) -> integer ``` Конвертирует массив байтов в 2-х байтовое знаковое число ```lua -function bit_converter.bytes_to_int32(table: bytes) -> integer +function bit_converter.bytes_to_sint32(bytes: table|Bytearray, [опционально] order: string) -> integer ``` Конвертирует массив байтов в 4-х байтовое знаковое число ```lua -function bit_converter.bytes_to_int64(table: bytes) -> integer +function bit_converter.bytes_to_int64(bytes: table|Bytearray, [опционально] order: string) -> integer ``` Конвертирует массив байтов в 8-х байтовое знаковое число diff --git a/doc/ru/scripting/modules/core_data_buffer.md b/doc/ru/scripting/modules/core_data_buffer.md index 60c36193..09b682b9 100644 --- a/doc/ru/scripting/modules/core_data_buffer.md +++ b/doc/ru/scripting/modules/core_data_buffer.md @@ -4,67 +4,78 @@ ### Хранит в себе массив байтов и позволяет легко получать или добавлять разные значения ```lua -function data_buffer(bytes) +function data_buffer( + [опционально] bytes: table, + [опционально] order: string, + [опционально] useBytearray: boolean +) ``` -Создаёт новый экземпляр data_buffer (параметр bytes необязательный) +Создаёт новый экземпляр **data_buffer**. +Если **useBytearray** равен **true**, то байты буффера будут хранится ввиде **Bytearray**. Это может снизить производительность, но также и уменьшить размер буффера в памяти ```lua -function data_buffer:put_byte(integer: byte) +function data_buffer:set_order(order: string) +``` +Задаёт порядок байтов для чисел. +Должен равняться одному из перечисленных в [**bit_converter**](core_bit_converter.md) + +```lua +function data_buffer:put_byte(byte: integer) ``` Записывает байт в буффер ```lua -function data_buffer:put_bytes(table: bytes) +function data_buffer:put_bytes(bytes: table|Bytearray) ``` Записывает байты в буффер ```lua -function data_buffer:put_string(string: str) +function data_buffer:put_string(str: string) ``` Конвертирует строку в байты и записывает их в буффер ```lua -function data_buffer:put_bool(boolean: bool) +function data_buffer:put_bool(bool: boolean) ``` Конвертирует булевое значение в байт и записывает его в буффер ```lua -function data_buffer:put_single(number: single) +function data_buffer:put_float32(float: number) ``` Конвертирует плавающее число одинарной точности в байты и записывает их в буффер ```lua -function data_buffer:put_double(number: double) +function data_buffer:put_float64(float: number) ``` Конвертирует плавающее число двойной точности в байты и записывает их в буффер ```lua -function data_buffer:put_uint16(integer: int) +function data_buffer:put_uint16(int: integer) ``` Конвертирует беззнаковое 2-х байтовое число в байты и записывает их в буффер ```lua -function data_buffer:put_uint32(integer: int) +function data_buffer:put_uint32(int: integer) ``` Конвертирует беззнаковое 4-х байтовое число в байты и записывает их в буффер ```lua -function data_buffer:put_int16(integer: int) +function data_buffer:put_sint16(int: integer) ``` Конвертирует знаковое 2-х байтовое число в байты и записывает их в буффер ```lua -function data_buffer:put_int32(integer: int) +function data_buffer:put_sint32(int: integer) ``` Конвертирует знаковое 4-х байтовое число в байты и записывает их в буффер ```lua -function data_buffer:put_int64(integer: int) +function data_buffer:put_int64(int: integer) ``` Конвертирует знаковое 8-и байтовое число в байты и записывает их в буффер ```lua -function data_buffer:put_number(number: num) +function data_buffer:put_number(num: number) ``` Конвертирует любое число в байты и записывает их в буффер; @@ -73,10 +84,10 @@ function data_buffer:put_number(number: num) zero = 0 uint16 = 1 uint32 = 2 -int16 = 3 -int32 = 4 int64 = 5 -double = 6 +float64 = 6 +sint16 = 7 +sint32 = 8 ``` ```lua @@ -85,9 +96,9 @@ function data_buffer:get_byte() -> integer Возвращает следующий байт из буффера ```lua -function data_buffer:get_bytes(n) -> table +function data_buffer:get_bytes(n) -> table|Bytearray ``` -Возвращает n следующих байтов, если n равен nil или не указан, то возвращается массив всех байтов +Возвращает **n** следующих байтов, если **n** равен **nil** или не указан, то возвращается массив всех байтов ```lua function data_buffer:get_string() -> string @@ -100,12 +111,12 @@ function data_buffer:get_bool() -> boolean Читает следующий логический булев из буффера ```lua -function data_buffer:get_single() -> number +function data_buffer:get_float32() -> number ``` Читает следующее плавающее число одинарной точности из буффера ```lua -function data_buffer:get_double() -> number +function data_buffer:get_float64() -> number ``` Читает следующее плавающее число двойной точности из буффера @@ -120,12 +131,12 @@ function data_buffer:get_uint32() -> integer Читает следующее 4-х байтовое беззнаковое целое число из буффера ```lua -function data_buffer:get_int16() -> integer +function data_buffer:get_sint16() -> integer ``` Читает следующее 2-х байтовое знаковое целое число из буффера ```lua -function data_buffer:get_int32() -> integer +function data_buffer:get_sint32() -> integer ``` Читает следующее 4-х байтовое знаковое целое число из буффера diff --git a/doc/ru/scripting/ui.md b/doc/ru/scripting/ui.md index 4d244210..07d93013 100644 --- a/doc/ru/scripting/ui.md +++ b/doc/ru/scripting/ui.md @@ -82,6 +82,8 @@ document["worlds-panel"]:clear() | textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") | | valid | bool | да | нет | является ли введенный текст корректным | | textColor | vec4 | да | да | цвет текста | +| syntax | string | да | да | подсветка синтаксиса ("lua" - Lua) | +| markup | string | да | да | язык разметки текста ("md" - Markdown) | Методы: @@ -139,9 +141,10 @@ document["worlds-panel"]:clear() Свойства: -| Название | Тип | Чтение | Запись | Описание | -| -------- | ------ | ------ | ------ | ----------- | -| text | string | да | да | текст метки | +| Название | Тип | Чтение | Запись | Описание | +| -------- | ------ | ------ | ------ | -------------------------------------- | +| text | string | да | да | текст метки | +| markup | string | да | да | язык разметки текста ("md" - Markdown) | ## Изображение (image) diff --git a/doc/ru/text-styles.md b/doc/ru/text-styles.md new file mode 100644 index 00000000..0a09abe3 --- /dev/null +++ b/doc/ru/text-styles.md @@ -0,0 +1,21 @@ +# Стили текста + +Для разметки стилей текста используется собственный диалект Markdown. +Форматирование работает на UI элементах: label и textbox, если явно указано `markup="md"`. + +## Стили + +| Стиль | Пример | Вывод | +| ------------ | ------------------------- | ----------------------------- | +| Жирный | `**Жирный шрифт**` | **Жирный шрифт** | +| Курсив | `*Текст курсивом*` | *Текст курсивом* | +| Подчеркнутый | `__Подчеркнутый текст__` | Подчеркнутый текст | +| Зачеркнутый | `~~Зачеркнутый текст~~` | ~~Зачеркнутый текст~~ | + +Стили могут объединяться. Пример: +```md +***__Сообщение__***, демонстрирующее *~~обедненные~~ объединенные* стили__~~.~~__ +``` +Вывод: + +***Сообщение***, демонстрирующее *~~обедненные~~ объединенные* стили~~.~~ diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md index 5c71690f..1ad93c4f 100644 --- a/doc/ru/xml-ui-layouts.md +++ b/doc/ru/xml-ui-layouts.md @@ -89,6 +89,7 @@ - `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта. - `multiline` - разрешает отображение многострочного текста. - `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true") +- `markup` - язык разметки текста ("md" - Markdown). ## Изображение - *image* @@ -113,6 +114,8 @@ - `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен. - `onup` - lua функция вызываемая при нажатии стрелки вверх. - `ondown` - lua функция вызываемая при нажатии стрелки вниз. +- `syntax` - подстветка синтаксиса ("lua" - Lua). +- `markup` - язык разметки текста ("md" - Markdown). ## Ползунок - *trackbar* diff --git a/flake.nix b/flake.nix index a1c9d20b..2c392d27 100644 --- a/flake.nix +++ b/flake.nix @@ -8,7 +8,7 @@ flake-utils.lib.eachDefaultSystem (system: { devShells.default = with nixpkgs.legacyPackages.${system}; mkShell { nativeBuildInputs = [ cmake pkg-config ]; - buildInputs = [ glm glfw glew zlib libpng libvorbis openal luajit ]; # libglvnd + buildInputs = [ glm glfw glew zlib libpng libvorbis openal luajit curl ]; # libglvnd packages = [ glfw mesa freeglut entt ]; LD_LIBRARY_PATH = "${wayland}/lib:$LD_LIBRARY_PATH"; }; diff --git a/res/content/base/package.json b/res/content/base/package.json index 7645a6e0..2878d3a6 100644 --- a/res/content/base/package.json +++ b/res/content/base/package.json @@ -1,6 +1,6 @@ { "id": "base", "title": "Base", - "version": "0.25", + "version": "0.26", "description": "basic content package" } diff --git a/res/layouts/console.xml b/res/layouts/console.xml index c367545c..43e72dd8 100644 --- a/res/layouts/console.xml +++ b/res/layouts/console.xml @@ -22,6 +22,7 @@ multiline='true' size-func="gui.get_viewport()[1],40" gravity="bottom-left" + markup="md" > MAX_UINT32 or int < MIN_UINT32 then error("invalid uint32") end - return { - intToByte(bit.rshift(int, 24)), - intToByte(bit.rshift(int, 16)), - intToByte(bit.rshift(int, 8)), - intToByte(int) - } + return uint32ToBytes(int, order) end -function bit_converter.uint16_to_bytes(int) +function bit_converter.uint16_to_bytes(int, order) if int > MAX_UINT16 or int < MIN_UINT16 then error("invalid uint16") end - return { - intToByte(bit.rshift(int, 8)), - intToByte(int) - } + return uint16ToBytes(int, order) end -function bit_converter.int64_to_bytes(int) +function bit_converter.int64_to_bytes(int, order) if int > MAX_INT64 or int < MIN_INT64 then error("invalid int64") end - return { - intToByte(bit.rshift(int, 56)), - intToByte(bit.rshift(int, 48)), - intToByte(bit.rshift(int, 40)), - intToByte(bit.rshift(int, 32)), - intToByte(bit.rshift(int, 24)), - intToByte(bit.rshift(int, 16)), - intToByte(bit.rshift(int, 8)), - intToByte(int) - } + return fromLE({ + maskHighBytes(bit.rshift(int, 56)), + maskHighBytes(bit.rshift(int, 48)), + maskHighBytes(bit.rshift(int, 40)), + maskHighBytes(bit.rshift(int, 32)), + maskHighBytes(bit.rshift(int, 24)), + maskHighBytes(bit.rshift(int, 16)), + maskHighBytes(bit.rshift(int, 8)), + maskHighBytes(int) + }, order) end -function bit_converter.int32_to_bytes(int) +function bit_converter.int32_to_bytes(int, order) + on_deprecated_call("bit_converter.int32_to_bytes", "bit_converter.sint32_to_bytes") + if int > MAX_INT32 or int < MIN_INT32 then error("invalid int32") end - return bit_converter.uint32_to_bytes(int + MAX_INT32) + return uint32ToBytes(int + MAX_INT32, order) end -function bit_converter.int16_to_bytes(int) +function bit_converter.int16_to_bytes(int, order) + on_deprecated_call("bit_converter.int32_to_bytes", "bit_converter.sint16_to_bytes") + if int > MAX_INT16 or int < MIN_INT16 then error("invalid int16") end - return bit_converter.uint16_to_bytes(int + MAX_INT16) + return uint16ToBytes(int + MAX_INT16, order) end -function bit_converter.bytes_to_single(bytes) - return bytesToFloatOrDouble(bytes, 'f') +function bit_converter.sint32_to_bytes(int, order) + if int > MAX_INT32 or int < MIN_INT32 then + error("invalid sint32") + end + + return uint32ToBytes(int + MAX_UINT32 + 1, order) end -function bit_converter.bytes_to_double(bytes) - return bytesToFloatOrDouble(bytes, 'd') +function bit_converter.sint16_to_bytes(int, order) + if int > MAX_INT16 or int < MIN_INT16 then + error("invalid sint16") + end + + return uint16ToBytes(int + MAX_UINT16 + 1, order) end -function bit_converter.bytes_to_string(bytes) +function bit_converter.bytes_to_float32(bytes, order) + return bytesToFloatOrDouble(toLE(bytes, order), 'f') +end + +function bit_converter.bytes_to_float64(bytes, order) + return bytesToFloatOrDouble(toLE(bytes, order), 'd') +end + +function bit_converter.bytes_to_single(bytes, order) + on_deprecated_call("bit_converter.bytes_to_single", "bit_converter.bytes_to_float32") + return bit_converter.bytes_to_float32(bytes, order) +end + +function bit_converter.bytes_to_double(bytes, order) + on_deprecated_call("bit_converter.bytes_to_double", "bit_converter.bytes_to_float64") + return bit_converter.bytes_to_float64(bytes, order) +end + +function bit_converter.bytes_to_string(bytes, order) local len = bit_converter.bytes_to_uint16({ bytes[1], bytes[2] }) local str = "" @@ -206,17 +287,13 @@ function bit_converter.byte_to_bool(byte) return byte ~= 0 end -function bit_converter.bytes_to_float(bytes) - if #bytes < 8 then - error("eof") - end - error("unsupported operation") -end - -function bit_converter.bytes_to_uint32(bytes) +function bit_converter.bytes_to_uint32(bytes, order) if #bytes < 4 then error("eof") end + + bytes = toLE(bytes, order) + return bit.bor( bit.bor( @@ -226,20 +303,26 @@ function bit_converter.bytes_to_uint32(bytes) bit.lshift(bytes[3], 8)),bytes[4]) end -function bit_converter.bytes_to_uint16(bytes) +function bit_converter.bytes_to_uint16(bytes, order) if #bytes < 2 then error("eof") end + + bytes = toLE(bytes, order) + return bit.bor( bit.lshift(bytes[1], 8), bytes[2], 0) end -function bit_converter.bytes_to_int64(bytes) +function bit_converter.bytes_to_int64(bytes, order) if #bytes < 8 then error("eof") end + + bytes = toLE(bytes, order) + return bit.bor( bit.bor( @@ -257,12 +340,26 @@ function bit_converter.bytes_to_int64(bytes) bit.lshift(bit.band(bytes[7], 0xFF), 8)),bit.band(bytes[8], 0xFF)) end -function bit_converter.bytes_to_int32(bytes) - return bit_converter.bytes_to_uint32(bytes) - MAX_INT32 +function bit_converter.bytes_to_int32(bytes, order) + on_deprecated_call("bit_converter.bytes_to_int32", "bit_converter.bytes_to_sint32") + return bit_converter.bytes_to_uint32(bytes, order) - MAX_INT32 end -function bit_converter.bytes_to_int16(bytes) - return bit_converter.bytes_to_uint16(bytes) - MAX_INT16 +function bit_converter.bytes_to_int16(bytes, order) + on_deprecated_call("bit_converter.bytes_to_int16", "bit_converter.bytes_to_sint16") + return bit_converter.bytes_to_uint16(bytes, order) - MAX_INT16 +end + +function bit_converter.bytes_to_sint32(bytes, order) + local num = bit_converter.bytes_to_uint32(bytes, order) + + return MIN_INT32 * (bit.band(MAX_INT32 + 1, num) ~= 0 and 1 or 0) + bit.band(MAX_INT32, num) +end + +function bit_converter.bytes_to_sint16(bytes, order) + local num = bit_converter.bytes_to_uint16(bytes, order) + + return MIN_INT16 * (bit.band(MAX_INT16 + 1, num) ~= 0 and 1 or 0) + bit.band(MAX_INT16, num) end return bit_converter diff --git a/res/modules/data_buffer.lua b/res/modules/data_buffer.lua index aafe63e7..e3d207ff 100644 --- a/res/modules/data_buffer.lua +++ b/res/modules/data_buffer.lua @@ -18,22 +18,31 @@ local TYPE_UINT32 = 2 local TYPE_INT16 = 3 local TYPE_INT32 = 4 local TYPE_INT64 = 5 -local TYPE_DOUBLE = 6 +local TYPE_FLOAT64 = 6 +local TYPE_SINT16 = 7 +local TYPE_SINT32 = 8 -- Data buffer local data_buffer = { __call = - function(data_buffer, bytes) - return data_buffer:new(bytes) + function(data_buffer, ...) + return data_buffer:new(...) end } -function data_buffer:new(bytes) +function data_buffer:new(bytes, order, useBytearray) + bytes = bytes or { } + + if order then bit_converter.validate_order(order) + else order = bit_converter.default_order end + local obj = { pos = 1, - bytes = bytes or { } + order = order, + useBytearray = useBytearray or false, + bytes = useBytearray and Bytearray(bytes) or bytes } self.__index = self @@ -42,6 +51,13 @@ function data_buffer:new(bytes) return obj end +function data_buffer:set_order(order) + bit_converter.validate_order(order) + + self.order = order + self.floatsOrder = order +end + -- Push functions function data_buffer:put_byte(byte) @@ -49,7 +65,8 @@ function data_buffer:put_byte(byte) error("invalid byte") end - self.bytes[self.pos] = byte + if self.useBytearray then self.bytes:insert(self.pos, byte) + else table.insert(self.bytes, self.pos, byte) end self.pos = self.pos + 1 end @@ -61,11 +78,21 @@ function data_buffer:put_bytes(bytes) end function data_buffer:put_single(single) - self:put_bytes(bit_converter.single_to_bytes(single)) + on_deprecated_call("data_buffer:put_single", "data_buffer:put_float32") + self:put_bytes(bit_converter.single_to_bytes(single, self.order)) end function data_buffer:put_double(double) - self:put_bytes(bit_converter.double_to_bytes(double)) + on_deprecated_call("data_buffer:put_single", "data_buffer:put_float64") + self:put_bytes(bit_converter.double_to_bytes(double, self.order)) +end + +function data_buffer:put_float32(single) + self:put_bytes(bit_converter.float32_to_bytes(single, self.order)) +end + +function data_buffer:put_float64(float) + self:put_bytes(bit_converter.float64_to_bytes(float, self.order)) end function data_buffer:put_string(str) @@ -77,23 +104,33 @@ function data_buffer:put_bool(bool) end function data_buffer:put_uint16(uint16) - self:put_bytes(bit_converter.uint16_to_bytes(uint16)) + self:put_bytes(bit_converter.uint16_to_bytes(uint16, self.order)) end function data_buffer:put_uint32(uint32) - self:put_bytes(bit_converter.uint32_to_bytes(uint32)) + self:put_bytes(bit_converter.uint32_to_bytes(uint32, self.order)) end function data_buffer:put_int16(int16) - self:put_bytes(bit_converter.int16_to_bytes(int16)) + on_deprecated_call("data_buffer:put_int16", "data_buffer:put_sint16") + self:put_bytes(bit_converter.int16_to_bytes(int16, self.order)) end function data_buffer:put_int32(int32) - self:put_bytes(bit_converter.int32_to_bytes(int32)) + on_deprecated_call("data_buffer:put_int32", "data_buffer:put_sint32") + self:put_bytes(bit_converter.int32_to_bytes(int32, self.order)) +end + +function data_buffer:put_sint16(int16) + self:put_bytes(bit_converter.sint16_to_bytes(int16, self.order)) +end + +function data_buffer:put_sint32(int32) + self:put_bytes(bit_converter.sint32_to_bytes(int32, self.order)) end function data_buffer:put_int64(int64) - self:put_bytes(bit_converter.int64_to_bytes(int64)) + self:put_bytes(bit_converter.int64_to_bytes(int64, self.order)) end function data_buffer:put_number(num) @@ -101,8 +138,8 @@ function data_buffer:put_number(num) local type if math.floor(num) ~= num then - type = TYPE_DOUBLE - bytes = bit_converter.double_to_bytes(num) + type = TYPE_FLOAT64 + bytes = bit_converter.float64_to_bytes(num) elseif num == 0 then type = TYPE_ZERO bytes = { } @@ -119,11 +156,11 @@ function data_buffer:put_number(num) end elseif num < 0 then if num >= MIN_INT16 then - type = TYPE_INT16 - bytes = bit_converter.int16_to_bytes(num) + type = TYPE_SINT16 + bytes = bit_converter.sint16_to_bytes(num) elseif num >= MIN_INT32 then - type = TYPE_INT32 - bytes = bit_converter.int32_to_bytes(num) + type = TYPE_SINT32 + bytes = bit_converter.sint32_to_bytes(num) elseif num >= MIN_INT64 then type = TYPE_INT64 bytes = bit_converter.int64_to_bytes(num) @@ -155,9 +192,13 @@ function data_buffer:get_number() return self:get_int16() elseif type == TYPE_INT32 then return self:get_int32() + elseif type == TYPE_SINT16 then + return self:get_sint16() + elseif type == TYPE_SINT32 then + return self:get_sint32() elseif type == TYPE_INT64 then return self:get_int64() - elseif type == TYPE_DOUBLE then + elseif type == TYPE_FLOAT64 then return self:get_double() else error("unknown lua number type: "..type) @@ -165,11 +206,21 @@ function data_buffer:get_number() end function data_buffer:get_single() - return bit_converter.bytes_to_single(self:get_bytes(4)) + on_deprecated_call("data_buffer:get_single", "data_buffer:get_float32") + return bit_converter.bytes_to_single(self:get_bytes(4), self.order) end function data_buffer:get_double() - return bit_converter.bytes_to_double(self:get_bytes(8)) + on_deprecated_call("data_buffer:get_double", "data_buffer:get_float64") + return bit_converter.bytes_to_double(self:get_bytes(8), self.order) +end + +function data_buffer:get_float32() + return bit_converter.bytes_to_float32(self:get_bytes(4), self.order) +end + +function data_buffer:get_float64() + return bit_converter.bytes_to_float64(self:get_bytes(8), self.order) end function data_buffer:get_string() @@ -193,23 +244,33 @@ function data_buffer:get_bool() end function data_buffer:get_uint16() - return bit_converter.bytes_to_uint16(self:get_bytes(2)) + return bit_converter.bytes_to_uint16(self:get_bytes(2), self.order) end function data_buffer:get_uint32() - return bit_converter.bytes_to_uint32(self:get_bytes(4)) + return bit_converter.bytes_to_uint32(self:get_bytes(4), self.order) end function data_buffer:get_int16() - return bit_converter.bytes_to_int16(self:get_bytes(2)) + on_deprecated_call("data_buffer:get_int16", "data_buffer:get_sint16") + return bit_converter.bytes_to_int16(self:get_bytes(2), self.order) end function data_buffer:get_int32() - return bit_converter.bytes_to_int32(self:get_bytes(4)) + on_deprecated_call("data_buffer:get_int32", "data_buffer:get_sint32") + return bit_converter.bytes_to_int32(self:get_bytes(4), self.order) +end + +function data_buffer:get_sint16() + return bit_converter.bytes_to_sint16(self:get_bytes(2), self.order) +end + +function data_buffer:get_sint32() + return bit_converter.bytes_to_sint32(self:get_bytes(4), self.order) end function data_buffer:get_int64() - return bit_converter.bytes_to_int64(self:get_bytes(8)) + return bit_converter.bytes_to_int64(self:get_bytes(8), self.order) end function data_buffer:size() diff --git a/res/scripts/classes.lua b/res/scripts/classes.lua index 200f305f..909717cf 100644 --- a/res/scripts/classes.lua +++ b/res/scripts/classes.lua @@ -42,6 +42,7 @@ local Socket = {__index={ close=function(self) return network.__close(self.id) end, is_alive=function(self) return network.__is_alive(self.id) end, is_connected=function(self) return network.__is_connected(self.id) end, + get_address=function(self) return network.__get_address(self.id) end, }} network.tcp_connect = function(address, port, callback) @@ -55,6 +56,7 @@ end local ServerSocket = {__index={ close=function(self) return network.__closeserver(self.id) end, is_open=function(self) return network.__is_serveropen(self.id) end, + get_port=function(self) return network.__get_serverport(self.id) end, }} network.tcp_open = function(port, handler) diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 14479c7d..13934e06 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -63,6 +63,20 @@ function table.copy(t) return copied end +function table.deep_copy(t) + local copied = {} + + for k, v in pairs(t) do + if type(v) == "table" then + copied[k] = table.deep_copy(v) + else + copied[k] = v + end + end + + return copied +end + function table.count_pairs(t) local count = 0 diff --git a/res/texts/uz_UZ.txt b/res/texts/uz_UZ.txt index 0ad6ec37..9d017ce9 100644 --- a/res/texts/uz_UZ.txt +++ b/res/texts/uz_UZ.txt @@ -1,4 +1,4 @@ -# Общее +# Umumiy Yes=Ha No=Yo'q Ok=Ок @@ -10,18 +10,26 @@ Version=Versiya Creator=Muallif Dependencies=Bog'liqliklar Description=Tavsif -Converting world...=Dunyoni konvertatsiyalash amalga oshirilyapti... +Converting world...=Dunyo konvertatsiya qilinmoqda... Unlimited=Cheksiz +Chat=Suhbat +Console=Konsol +Log=log +Problems=Muammolar +Monitor=Monitoring +Debug=Xatolarni tuzatish (Debug) +File=Fayl +devtools.traceback=Chaqiruvlar steki (so‘nggisidan boshlab) error.pack-not-found=Paketni topib bo'lmadi error.dependency-not-found=Amaldagi qaramliklar topilmadi -pack.remove-confirm=Paketlar bilan taqdim etilgan barcha mazmunni dunyodan olib tashlash (qaytarib bo'lmaydi)? +pack.remove-confirm=Paketlar bilan taqdim etilgan barcha contentni dunyodan olib tashlash (qaytarib bo'lmaydi)? -# Подсказки +# Maslahatlar graphics.gamma.tooltip=Yorug'lik yorqinligi egri chizig'i graphics.backlight.tooltip=To'liq zulmatni oldini oladigan orqa yorug'ligi -# Меню +# Menyu menu.Apply=Qo'llash menu.Audio=Tovush menu.Back to Main Menu=Menyuga qaytish @@ -31,61 +39,73 @@ menu.Continue=Davom ettirish menu.Controls=Boshqaruv menu.Display=Displey menu.Graphics=Grafika -menu.missing-content=Kontent etishmayapti! +menu.missing-content=Kontent mavjud emas! menu.New World=Yangi Dunyo -menu.Worlds=Dunyo -menu.Open worlds folder=Dunyo papkasini ochish +menu.Open worlds folder=Dunyolar papkasini ochish +menu.Worlds=Dunyolar menu.Page not found=Sahifa topilmadi menu.Quit=Chiqish -menu.Save and Quit to Menu=Saqlash va menyuga chiqish +menu.Save and Quit to Menu=Saqlash va Menyuga chiqish menu.Settings=Sozlamalar -menu.Contents Menu=Kontent to'plamlari menyusi +menu.Reset settings=Sozlamalarni tiklash +menu.Contents Menu=Kontent paklar menyusi +menu.Open data folder=Ma'lumotlar papkasini ochish +menu.Open content folder=[content] papkasini ochish world.Seed=Don world.Name=Nom -world.World generator=Dunyo yaratuvchi -world.generators.default=Oddiy -world.generators.flat=Yassi -world.Create World=Dunyoni Yaratish -world.convert-request=Indekslarda o‘zgarishlar mavjud! Dunyoni konvertatsiya qilish kerakmi? -world.delete-confirm=Dunyoni qaytarib bo'lmaydigan tarzda olib tashlaysizmi? +world.World generator=Dunyo generatori +world.generators.default=Standart bo'yicha +world.generators.flat=Tekis +world.Create World=Dunyo yaratish +world.convert-request=Indekslar bo'yicha o'zgarishlar bor! Dunyoni konvertatsiya qilasizmi? +world.upgrade-request=Dunyo formati eskirgan! Dunyoni konvertatsiya qilasizmi? +world.convert-with-loss=Dunyoni yo'qotishlar bilan konvertatsiya qilasizmi? +world.convert-block-layouts=Blok maydonlarida o'zgarishlar bor! Dunyoni konvertatsiya qilasizmi? +world.delete-confirm=Dunyoni doimiy o'chirasizmi? -# Настройки +# Sozlamalar settings.Ambient=Fon settings.Backlight=Yoritish -settings.Camera Shaking=Kamera Silkinishi -settings.Camera Inertia=Kamera Inertsiyasi -settings.Fog Curve=Tuman Egri Chizig'i -settings.FOV=Ko'rish Maydoni +settings.Camera Shaking=Kamera titrashi +settings.Camera Inertia=Kamera inertsiyasi +settings.Camera FOV Effects=Ko'rish maydoni effektlari +settings.Fog Curve=Tuman egri chizig'i +settings.FOV=Ko'rish maydoni settings.Fullscreen=To'liq ekran -settings.Framerate=Kadr tezligi +settings.Framerate=Kadrlar chastotasi settings.Gamma=Gamma settings.Language=Til -settings.Load Distance=Yuklash Masofasi -settings.Load Speed=Yuklash Tezligi -settings.Master Volume=Umumiy Ovoz Balandligi -settings.Mouse Sensitivity=Sichqoncha Sezgirligi +settings.Load Distance=Yuklash masofasi +settings.Load Speed=Yuklash tezligi +settings.Master Volume=Umumiy ovoz balansi +settings.Mouse Sensitivity=Sichqoncha sezgirligi settings.Music=Musiqa -settings.Regular Sounds=Oddiy Tovushlar -settings.UI Sounds=Interfeys Tovushlari -settings.V-Sync=Vertikal Sinxronizatsiya +settings.Regular Sounds=Oddiy tovushlar +settings.UI Sounds=Interfeys tovushlari +settings.V-Sync=Vertikal sinxronizatsiya +settings.Key=Tugma +settings.Controls Search Mode=Tayinlangan boshqaruv tugmasi bo'yicha qidirish +settings.Limit Background FPS=Fon kadrlar chastotasini cheklash -# Управление +# Boshqaruv chunks.reload=Chanklarni qayta yuklash devtools.console=Konsol movement.forward=Oldinga movement.back=Orqaga movement.left=Chapga -movement.right=O'ng tomonda +movement.right=O'ngga movement.jump=Sakrash -movement.sprint=Tezlanish +movement.sprint=Tez yugurish movement.crouch=Egilish -movement.cheat=Chit -hud.inventory=inventar +movement.cheat=Hiyla (Chit) +hud.inventory=Inventar player.pick=Blokni olish -player.attack=Hujum Qilish / Sindirish -player.build=Blokni Joylashtiring +player.attack=Hujum qilish +player.destroy=Sindirish +player.build=Blokni qo'yish +player.fast_interaction=Tezkor o'zaro ta'sir player.flight=Parvoz player.drop=Narsani tashlash camera.zoom=Yaqinlashish -camera.mode=Kamera Rejimini O'zgartiring +camera.mode=Kamera Rejimini O'zgartiring \ No newline at end of file diff --git a/src/coders/commons.cpp b/src/coders/commons.cpp index de4fb755..cd9a2d4c 100644 --- a/src/coders/commons.cpp +++ b/src/coders/commons.cpp @@ -214,6 +214,28 @@ std::string_view BasicParser::readUntil(char c) { return source.substr(start, pos - start); } +std::string_view BasicParser::readUntil(std::string_view s, bool nothrow) { + int start = pos; + size_t found = source.find(s, pos); + if (found == std::string::npos) { + if (nothrow) { + pos = source.size(); + return source.substr(start); + } + throw error(util::quote(std::string(s))+" expected"); + } + skip(found - pos); + return source.substr(start, pos - start); +} + +std::string_view BasicParser::readUntilWhitespace() { + int start = pos; + while (hasNext() && !is_whitespace(source[pos])) { + pos++; + } + return source.substr(start, pos - start); +} + std::string_view BasicParser::readUntilEOL() { int start = pos; while (hasNext() && source[pos] != '\r' && source[pos] != '\n') { diff --git a/src/coders/commons.hpp b/src/coders/commons.hpp index abd4c01a..9251d57d 100644 --- a/src/coders/commons.hpp +++ b/src/coders/commons.hpp @@ -105,6 +105,8 @@ protected: parsing_error error(const std::string& message); public: std::string_view readUntil(char c); + std::string_view readUntil(std::string_view s, bool nothrow); + std::string_view readUntilWhitespace(); std::string_view readUntilEOL(); std::string parseName(); std::string parseXmlName(); diff --git a/src/coders/json.cpp b/src/coders/json.cpp index 017f7d26..0990ff47 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -11,15 +11,17 @@ using namespace json; -class Parser : BasicParser { - dv::value parseList(); - dv::value parseObject(); - dv::value parseValue(); -public: - Parser(std::string_view filename, std::string_view source); +namespace { + class Parser : BasicParser { + dv::value parseList(); + dv::value parseObject(); + dv::value parseValue(); + public: + Parser(std::string_view filename, std::string_view source); - dv::value parse(); -}; + dv::value parse(); + }; +} inline void newline( std::stringstream& ss, bool nice, uint indent, const std::string& indentstr diff --git a/src/coders/lua_parsing.cpp b/src/coders/lua_parsing.cpp new file mode 100644 index 00000000..f30aab37 --- /dev/null +++ b/src/coders/lua_parsing.cpp @@ -0,0 +1,188 @@ +#include "lua_parsing.hpp" + +#include + +#include "commons.hpp" + +using namespace lua; +using namespace devtools; + +static std::set keywords { + "and", "break", "do", "else", "elseif", "end", "false", "for", "function", + "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", + "until", "while" +}; + +bool lua::is_lua_keyword(std::string_view view) { + return keywords.find(view) != keywords.end(); +} + +inline bool is_lua_identifier_start(int c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; +} + +inline bool is_lua_identifier_part(int c) { + return is_lua_identifier_start(c) || is_digit(c); +} + +inline bool is_lua_operator_start(int c) { + return c == '=' || c == '~' || c == '+' || c == '-' || c == '/' || c == '*' + || c == '%' || c == '^' || c == '#' || c == '<' || c == '>' || c == ':' + || c == '.'; +} + +class Tokenizer : BasicParser { + std::vector tokens; +public: + Tokenizer(std::string_view file, std::string_view source) + : BasicParser(file, source) { + } + + std::string parseLuaName() { + char c = peek(); + if (!is_identifier_start(c)) { + throw error("identifier expected"); + } + int start = pos; + while (hasNext() && is_identifier_part(source[pos])) { + pos++; + } + return std::string(source.substr(start, pos - start)); + } + + inline Location currentLocation() const { + return Location { + static_cast(pos), + static_cast(linestart), + static_cast(line)}; + } + + void emitToken( + TokenTag tag, std::string name, Location start, bool standalone=false + ) { + tokens.emplace_back( + tag, + std::move(name), + std::move(start), + currentLocation() + ); + if (standalone) skip(1); + } + + /// @brief Get next operator token without checking operator for existing + std::string parseOperator() { + int start = pos; + char first = peek(); + switch (first) { + case '#': case '+': case '/': case '*': case '^': + case '%': + skip(1); + return std::string({first}); + case '-': + skip(1); + if (peekNoJump() == '-') { + skip(1); + return "--"; + } + return std::string({first}); + } + skip(1); + char second = peekNoJump(); + if ((first == '=' && second == '=') || (first == '~' && second == '=') || + (first == '<' && second == '=') || (first == '>' && second == '=')) { + skip(1); + return std::string(source.substr(start, pos - start)); + } + if (first == '.' && second == '.') { + skip(1); + if (peekNoJump() == '.') { + skip(1); + } + } + return std::string(source.substr(start, pos - start)); + } + + std::vector tokenize() { + skipWhitespace(); + while (hasNext()) { + skipWhitespace(); + if (!hasNext()) { + continue; + } + char c = peek(); + auto start = currentLocation(); + if (is_lua_identifier_start(c)) { + auto name = parseLuaName(); + emitToken( + is_lua_keyword(name) ? TokenTag::KEYWORD : TokenTag::NAME, + std::move(name), + start + ); + continue; + } else if (is_digit(c)) { + dv::value value; + auto tag = TokenTag::UNEXPECTED; + try { + value = parseNumber(1); + tag = value.isInteger() ? TokenTag::INTEGER + : TokenTag::NUMBER; + } catch (const parsing_error& err) {} + + auto literal = source.substr(start.pos, pos - start.pos); + emitToken(tag, std::string(literal), start); + continue; + } + switch (c) { + case '(': case '[': case '{': + if (isNext("[==[")) { + auto string = readUntil("]==]", true); + skip(4); + emitToken(TokenTag::COMMENT, std::string(string)+"]==]", start); + continue; + } else if (isNext("[[")) { + skip(2); + auto string = readUntil("]]", true); + skip(2); + emitToken(TokenTag::STRING, std::string(string), start); + continue; + } + emitToken(TokenTag::OPEN_BRACKET, std::string({c}), start, true); + continue; + case ')': case ']': case '}': + emitToken(TokenTag::CLOSE_BRACKET, std::string({c}), start, true); + continue; + case ',': + emitToken(TokenTag::COMMA, std::string({c}), start, true); + continue; + case ';': + emitToken(TokenTag::SEMICOLON, std::string({c}), start, true); + continue; + case '\'': case '"': { + skip(1); + auto string = parseString(c, false); + emitToken(TokenTag::STRING, std::move(string), start); + continue; + } + default: break; + } + if (is_lua_operator_start(c)) { + auto text = parseOperator(); + if (text == "--") { + auto string = readUntilEOL(); + emitToken(TokenTag::COMMENT, std::string(string), start); + skipLine(); + continue; + } + emitToken(TokenTag::OPERATOR, std::move(text), start); + continue; + } + auto text = readUntilWhitespace(); + emitToken(TokenTag::UNEXPECTED, std::string(text), start); + } + return std::move(tokens); + } +}; + +std::vector lua::tokenize(std::string_view file, std::string_view source) { + return Tokenizer(file, source).tokenize(); +} diff --git a/src/coders/lua_parsing.hpp b/src/coders/lua_parsing.hpp new file mode 100644 index 00000000..0054e4d0 --- /dev/null +++ b/src/coders/lua_parsing.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include "devtools/syntax.hpp" + +namespace lua { + bool is_lua_keyword(std::string_view view); + + std::vector tokenize( + std::string_view file, std::string_view source + ); +} diff --git a/src/coders/png.cpp b/src/coders/png.cpp index 60965ed1..b29afd34 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -13,7 +13,7 @@ static debug::Logger logger("png-coder"); // returns 0 if all-right, 1 otherwise -int _png_write( +static int png_write( const char* filename, uint width, uint height, const ubyte* data, bool alpha ) { uint pixsize = alpha ? 4 : 3; @@ -112,7 +112,7 @@ static void read_in_memory(png_structp pngPtr, png_bytep dst, png_size_t toread) } std::unique_ptr png::load_image(const ubyte* bytes, size_t size) { - if (!png_check_sig(bytes, size)) { + if (size < 8 || !png_check_sig(bytes, 8)) { throw std::runtime_error("invalid png signature"); } png_structp pngPtr = nullptr; @@ -223,7 +223,7 @@ std::unique_ptr png::load_texture(const std::string& filename) { } void png::write_image(const std::string& filename, const ImageData* image) { - _png_write( + png_write( filename.c_str(), image->getWidth(), image->getHeight(), diff --git a/src/coders/xml.cpp b/src/coders/xml.cpp index faf84f15..b2cb8809 100644 --- a/src/coders/xml.cpp +++ b/src/coders/xml.cpp @@ -107,8 +107,8 @@ glm::vec4 Attribute::asColor() const { Node::Node(std::string tag) : tag(std::move(tag)) { } -void Node::add(const xmlelement& element) { - elements.push_back(element); +void Node::add(std::unique_ptr element) { + elements.push_back(std::move(element)); } void Node::set(const std::string& name, const std::string& text) { @@ -119,7 +119,7 @@ const std::string& Node::getTag() const { return tag; } -const xmlattribute& Node::attr(const std::string& name) const { +const Attribute& Node::attr(const std::string& name) const { auto found = attrs.find(name); if (found == attrs.end()) { throw std::runtime_error( @@ -129,7 +129,7 @@ const xmlattribute& Node::attr(const std::string& name) const { return found->second; } -xmlattribute Node::attr(const std::string& name, const std::string& def) const { +Attribute Node::attr(const std::string& name, const std::string& def) const { auto found = attrs.find(name); if (found == attrs.end()) { return Attribute(name, def); @@ -142,19 +142,23 @@ bool Node::has(const std::string& name) const { return found != attrs.end(); } -xmlelement Node::sub(size_t index) { - return elements.at(index); +Node& Node::sub(size_t index) { + return *elements.at(index); +} + +const Node& Node::sub(size_t index) const { + return *elements.at(index); } size_t Node::size() const { return elements.size(); } -const std::vector& Node::getElements() const { +const std::vector>& Node::getElements() const { return elements; } -const xmlelements_map& Node::getAttributes() const { +const std::unordered_map& Node::getAttributes() const { return attrs; } @@ -162,12 +166,12 @@ Document::Document(std::string version, std::string encoding) : version(std::move(version)), encoding(std::move(encoding)) { } -void Document::setRoot(const xmlelement& element) { - this->root = element; +void Document::setRoot(std::unique_ptr element) { + root = std::move(element); } -xmlelement Document::getRoot() const { - return root; +const Node* Document::getRoot() const { + return root.get(); } const std::string& Document::getVersion() const { @@ -178,82 +182,6 @@ const std::string& Document::getEncoding() const { return encoding; } -Parser::Parser(std::string_view filename, std::string_view source) - : BasicParser(filename, source) { -} - -xmlelement Parser::parseOpenTag() { - std::string tag = parseXMLName(); - auto node = std::make_shared(tag); - - char c; - while (true) { - skipWhitespace(); - c = peek(); - if (c == '/' || c == '>' || c == '?') break; - std::string attrname = parseXMLName(); - std::string attrtext = ""; - skipWhitespace(); - if (peek() == '=') { - nextChar(); - skipWhitespace(); - - char quote = peek(); - if (quote != '\'' && quote != '"') { - throw error("string literal expected"); - } - skip(1); - attrtext = parseString(quote); - } - node->set(attrname, attrtext); - } - return node; -} - -void Parser::parseDeclaration() { - std::string version = "1.0"; - std::string encoding = "UTF-8"; - expect('<'); - if (peek() == '?') { - nextChar(); - xmlelement node = parseOpenTag(); - expect("?>"); - if (node->getTag() != "xml") { - throw error("invalid declaration"); - } - version = node->attr("version", version).getText(); - encoding = node->attr("encoding", encoding).getText(); - if (encoding != "utf-8" && encoding != "UTF-8") { - throw error("UTF-8 encoding is only supported"); - } - } else { - goBack(); - } - document = std::make_shared(version, encoding); -} - -void Parser::parseComment() { - expect("!--"); - if (skipTo("-->")) { - skip(3); - } else { - throw error("comment close missing"); - } -} - -std::string Parser::parseText() { - size_t start = pos; - while (hasNext()) { - char c = peek(); - if (c == '<') { - break; - } - nextChar(); - } - return Parser("[string]", std::string(source.substr(start, pos - start))) - .parseString('\0', false); -} - inline bool is_xml_identifier_start(char c) { return is_identifier_start(c) || c == ':'; } @@ -262,82 +190,166 @@ inline bool is_xml_identifier_part(char c) { return is_identifier_part(c) || c == '-' || c == '.' || c == ':'; } -std::string Parser::parseXMLName() { - char c = peek(); - if (!is_xml_identifier_start(c)) { - throw error("identifier expected"); - } - int start = pos; - while (hasNext() && is_xml_identifier_part(source[pos])) { - pos++; - } - return std::string(source.substr(start, pos - start)); -} +namespace { +class Parser : BasicParser { + std::unique_ptr document; -xmlelement Parser::parseElement() { - // text element - if (peek() != '<') { - auto element = std::make_shared("#"); - auto text = parseText(); - util::replaceAll(text, """, "\""); - util::replaceAll(text, "'", "'"); - util::replaceAll(text, "<", "<"); - util::replaceAll(text, ">", ">"); - util::replaceAll(text, "&", "&"); - element->set("#", text); + std::unique_ptr parseOpenTag() { + std::string tag = parseXMLName(); + auto node = std::make_unique(tag); + + char c; + while (true) { + skipWhitespace(); + c = peek(); + if (c == '/' || c == '>' || c == '?') break; + std::string attrname = parseXMLName(); + std::string attrtext = ""; + skipWhitespace(); + if (peek() == '=') { + nextChar(); + skipWhitespace(); + + char quote = peek(); + if (quote != '\'' && quote != '"') { + throw error("string literal expected"); + } + skip(1); + attrtext = parseString(quote); + } + node->set(attrname, attrtext); + } + return node; + } + + std::unique_ptr parseElement() { + // text element + if (peek() != '<') { + auto element = std::make_unique("#"); + auto text = parseText(); + util::replaceAll(text, """, "\""); + util::replaceAll(text, "'", "'"); + util::replaceAll(text, "<", "<"); + util::replaceAll(text, ">", ">"); + util::replaceAll(text, "&", "&"); + element->set("#", text); + return element; + } + nextChar(); + + // + if (peek() == '!') { + if (isNext("!DOCTYPE ")) { + throw error("XML DTD is not supported yet"); + } + parseComment(); + return nullptr; + } + + auto element = parseOpenTag(); + char c = nextChar(); + + // + if (c == '/') { + expect('>'); + } + // ... + else if (c == '>') { + skipWhitespace(); + while (!isNext("add(std::move(sub)); + } + skipWhitespace(); + } + skip(2); + expect(element->getTag()); + expect('>'); + } + // + else { + throw error("invalid syntax"); + } return element; } - nextChar(); - // - if (peek() == '!') { - if (isNext("!DOCTYPE ")) { - throw error("XML DTD is not supported yet"); - } - parseComment(); - return nullptr; - } - - auto element = parseOpenTag(); - char c = nextChar(); - - // - if (c == '/') { - expect('>'); - } - // ... - else if (c == '>') { - skipWhitespace(); - while (!isNext("add(sub); + void parseDeclaration() { + std::string version = "1.0"; + std::string encoding = "UTF-8"; + expect('<'); + if (peek() == '?') { + nextChar(); + auto node = parseOpenTag(); + expect("?>"); + if (node->getTag() != "xml") { + throw error("invalid declaration"); } - skipWhitespace(); + version = node->attr("version", version).getText(); + encoding = node->attr("encoding", encoding).getText(); + if (encoding != "utf-8" && encoding != "UTF-8") { + throw error("UTF-8 encoding is only supported"); + } + } else { + goBack(); } - skip(2); - expect(element->getTag()); - expect('>'); + document = std::make_unique(version, encoding); } - // - else { - throw error("invalid syntax"); + + void parseComment() { + expect("!--"); + if (skipTo("-->")) { + skip(3); + } else { + throw error("comment close missing"); + } } - return element; + + std::string parseText() { + size_t start = pos; + while (hasNext()) { + char c = peek(); + if (c == '<') { + break; + } + nextChar(); + } + return Parser("[string]", std::string(source.substr(start, pos - start))) + .parseString('\0', false); + } + + std::string parseXMLName() { + char c = peek(); + if (!is_xml_identifier_start(c)) { + throw error("identifier expected"); + } + int start = pos; + while (hasNext() && is_xml_identifier_part(source[pos])) { + pos++; + } + return std::string(source.substr(start, pos - start)); + } +public: + Parser(std::string_view filename, std::string_view source) + : BasicParser(filename, source) { + } + + std::unique_ptr parse() { + parseDeclaration(); + + std::unique_ptr root; + while (root == nullptr) { + root = parseElement(); + } + document->setRoot(std::move(root)); + return std::move(document); + } +}; } -xmldocument Parser::parse() { - parseDeclaration(); - - xmlelement root = nullptr; - while (root == nullptr) { - root = parseElement(); - } - document->setRoot(root); - return document; -} - -xmldocument xml::parse(std::string_view filename, std::string_view source) { +std::unique_ptr xml::parse( + std::string_view filename, std::string_view source +) { Parser parser(filename, source); return parser.parse(); } @@ -354,13 +366,13 @@ inline void newline( static void stringifyElement( std::stringstream& ss, - const xmlelement& element, + const Node& element, bool nice, const std::string& indentStr, int indent ) { - if (element->isText()) { - std::string text = element->attr("#").getText(); + if (element.isText()) { + std::string text = element.attr("#").getText(); util::replaceAll(text, "&", "&"); util::replaceAll(text, "\"", """); util::replaceAll(text, "'", "'"); @@ -369,10 +381,10 @@ static void stringifyElement( ss << text; return; } - const std::string& tag = element->getTag(); + const std::string& tag = element.getTag(); ss << '<' << tag; - auto& attrs = element->getAttributes(); + auto& attrs = element.getAttributes(); if (!attrs.empty()) { ss << ' '; int count = 0; @@ -388,10 +400,10 @@ static void stringifyElement( count++; } } - auto& elements = element->getElements(); + auto& elements = element.getElements(); if (elements.size() == 1 && elements[0]->isText()) { ss << ">"; - stringifyElement(ss, elements[0], nice, indentStr, indent + 1); + stringifyElement(ss, *elements[0], nice, indentStr, indent + 1); ss << ""; return; } @@ -399,7 +411,7 @@ static void stringifyElement( ss << '>'; for (auto& sub : elements) { newline(ss, nice, indentStr, indent + 1); - stringifyElement(ss, sub, nice, indentStr, indent + 1); + stringifyElement(ss, *sub, nice, indentStr, indent + 1); } newline(ss, nice, indentStr, indent); ss << ""; @@ -410,16 +422,16 @@ static void stringifyElement( } std::string xml::stringify( - const xmldocument& document, bool nice, const std::string& indentStr + const Document& document, bool nice, const std::string& indentStr ) { std::stringstream ss; // XML declaration - ss << "getVersion(); + ss << ""; newline(ss, nice, indentStr, 0); - stringifyElement(ss, document->getRoot(), nice, indentStr, 0); + stringifyElement(ss, *document.getRoot(), nice, indentStr, 0); return ss.str(); } diff --git a/src/coders/xml.hpp b/src/coders/xml.hpp index 54a2b589..5831c29a 100644 --- a/src/coders/xml.hpp +++ b/src/coders/xml.hpp @@ -13,11 +13,6 @@ namespace xml { class Attribute; class Document; - using xmlattribute = Attribute; - using xmlelement = std::shared_ptr; - using xmldocument = std::shared_ptr; - using xmlelements_map = std::unordered_map; - class Attribute { std::string name; std::string text; @@ -40,13 +35,15 @@ namespace xml { /// 'text' class Node { std::string tag; - std::unordered_map attrs; - std::vector elements; + std::unordered_map attrs; + std::vector> elements; public: Node(std::string tag); + Node(const Node&) = delete; + /// @brief Add sub-element - void add(const xmlelement& element); + void add(std::unique_ptr element); /// @brief Set attribute value. Creates attribute if does not exists /// @param name attribute name @@ -67,15 +64,15 @@ namespace xml { /// @brief Get attribute by name /// @param name attribute name /// @throws std::runtime_error if element has no attribute - /// @return xmlattribute - {name, value} - const xmlattribute& attr(const std::string& name) const; + /// @return xml attribute - {name, value} + const Attribute& attr(const std::string& name) const; /// @brief Get attribute by name /// @param name attribute name /// @param def default value will be returned wrapped in xmlattribute /// if element has no attribute - /// @return xmlattribute - {name, value} or {name, def} if not found*/ - xmlattribute attr(const std::string& name, const std::string& def) + /// @return xml attribute - {name, value} or {name, def} if not found + Attribute attr(const std::string& name, const std::string& def) const; /// @brief Check if element has attribute @@ -86,51 +83,37 @@ namespace xml { /// @param index sub-element index /// @throws std::out_of_range if an invalid index given /// @return sub-element - xmlelement sub(size_t index); + Node& sub(size_t index); + const Node& sub(size_t index) const; /// @brief Get number of sub-elements size_t size() const; - const std::vector& getElements() const; - const xmlelements_map& getAttributes() const; + const std::vector>& getElements() const; + const std::unordered_map& getAttributes() const; }; class Document { - xmlelement root = nullptr; + std::unique_ptr root = nullptr; std::string version; std::string encoding; public: Document(std::string version, std::string encoding); - void setRoot(const xmlelement& element); - xmlelement getRoot() const; + void setRoot(std::unique_ptr element); + const Node* getRoot() const; const std::string& getVersion() const; const std::string& getEncoding() const; }; - class Parser : BasicParser { - xmldocument document; - - xmlelement parseOpenTag(); - xmlelement parseElement(); - void parseDeclaration(); - void parseComment(); - std::string parseText(); - std::string parseXMLName(); - public: - Parser(std::string_view filename, std::string_view source); - - xmldocument parse(); - }; - /// @brief Serialize XML Document to string /// @param document serializing document /// @param nice use human readable format (with indents and line-separators) /// @param indentStr indentation characters sequence (default - 4 spaces) /// @return XML string - extern std::string stringify( - const xmldocument& document, + std::string stringify( + const Document& document, bool nice = true, const std::string& indentStr = " " ); @@ -139,7 +122,9 @@ namespace xml { /// @param filename file name will be shown in error messages /// @param source xml source code string /// @return xml document - extern xmldocument parse( + std::unique_ptr parse( std::string_view filename, std::string_view source ); + + using xmlelement = Node; } diff --git a/src/constants.hpp b/src/constants.hpp index 84d8b22c..c8de5a8d 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -6,7 +6,7 @@ #include inline constexpr int ENGINE_VERSION_MAJOR = 0; -inline constexpr int ENGINE_VERSION_MINOR = 25; +inline constexpr int ENGINE_VERSION_MINOR = 26; #ifdef NDEBUG inline constexpr bool ENGINE_DEBUG_BUILD = false; @@ -14,7 +14,7 @@ inline constexpr bool ENGINE_DEBUG_BUILD = false; inline constexpr bool ENGINE_DEBUG_BUILD = true; #endif // NDEBUG -inline const std::string ENGINE_VERSION_STRING = "0.25"; +inline const std::string ENGINE_VERSION_STRING = "0.26"; /// @brief world regions format version inline constexpr uint REGION_FORMAT_VERSION = 3; diff --git a/src/devtools/syntax.hpp b/src/devtools/syntax.hpp new file mode 100644 index 00000000..6c7d4b15 --- /dev/null +++ b/src/devtools/syntax.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace devtools { + struct Location { + int pos; + int lineStart; + int line; + }; + + enum class TokenTag { + KEYWORD, NAME, INTEGER, NUMBER, OPEN_BRACKET, CLOSE_BRACKET, STRING, + OPERATOR, COMMA, SEMICOLON, UNEXPECTED, COMMENT + }; + + struct Token { + TokenTag tag; + std::string text; + Location start; + Location end; + + Token(TokenTag tag, std::string text, Location start, Location end) + : tag(tag), + text(std::move(text)), + start(std::move(start)), + end(std::move(end)) { + } + }; +} diff --git a/src/devtools/syntax_highlighting.cpp b/src/devtools/syntax_highlighting.cpp new file mode 100644 index 00000000..f68780df --- /dev/null +++ b/src/devtools/syntax_highlighting.cpp @@ -0,0 +1,72 @@ +#include "syntax_highlighting.hpp" + +#include "coders/commons.hpp" +#include "coders/lua_parsing.hpp" +#include "graphics/core/Font.hpp" + +using namespace devtools; + +static std::unique_ptr build_styles( + const std::vector& tokens +) { + using devtools::TokenTag; + FontStylesScheme styles { + { + {false, false, false, false, glm::vec4(0.8f, 0.8f, 0.8f, 1)}, // default + {true, false, false, false, glm::vec4(0.9, 0.6f, 0.4f, 1)}, // keyword + {false, false, false, false, glm::vec4(0.4, 0.8f, 0.5f, 1)}, // string + {false, false, false, false, glm::vec4(0.3, 0.3f, 0.3f, 1)}, // comment + {true, false, false, false, glm::vec4(1.0f, 0.2f, 0.1f, 1)}, // unexpected + }, + {} + }; + size_t offset = 0; + for (int i = 0; i < tokens.size(); i++) { + const auto& token = tokens.at(i); + if (token.tag != TokenTag::KEYWORD && + token.tag != TokenTag::STRING && + token.tag != TokenTag::INTEGER && + token.tag != TokenTag::NUMBER && + token.tag != TokenTag::COMMENT && + token.tag != TokenTag::UNEXPECTED) { + continue; + } + if (token.start.pos > offset) { + int n = token.start.pos - offset; + styles.map.insert(styles.map.end(), token.start.pos - offset, 0); + } + offset = token.end.pos; + int styleIndex; + switch (token.tag) { + case TokenTag::KEYWORD: styleIndex = SyntaxStyles::KEYWORD; break; + case TokenTag::STRING: + case TokenTag::INTEGER: + case TokenTag::NUMBER: styleIndex = SyntaxStyles::LITERAL; break; + case TokenTag::COMMENT: styleIndex = SyntaxStyles::COMMENT; break; + case TokenTag::UNEXPECTED: styleIndex = SyntaxStyles::ERROR; break; + default: + styleIndex = 0; + break; + } + styles.map.insert( + styles.map.end(), token.end.pos - token.start.pos, styleIndex + ); + } + styles.map.push_back(0); + return std::make_unique(std::move(styles)); +} + +std::unique_ptr devtools::syntax_highlight( + const std::string& lang, std::string_view source +) { + try { + if (lang == "lua") { + auto tokens = lua::tokenize("", source); + return build_styles(tokens); + } else { + return nullptr; + } + } catch (const parsing_error& err) { + return nullptr; + } +} diff --git a/src/devtools/syntax_highlighting.hpp b/src/devtools/syntax_highlighting.hpp new file mode 100644 index 00000000..18db6389 --- /dev/null +++ b/src/devtools/syntax_highlighting.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +struct FontStylesScheme; + +namespace devtools { + enum SyntaxStyles { + DEFAULT, KEYWORD, LITERAL, COMMENT, ERROR + }; + + std::unique_ptr syntax_highlight( + const std::string& lang, std::string_view source + ); +} diff --git a/src/engine.cpp b/src/engine.cpp index 31db4537..129dc68d 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -206,7 +206,7 @@ void Engine::renderFrame(Batch2D& batch) { Viewport viewport(Window::width, Window::height); DrawContext ctx(nullptr, viewport, &batch); - gui->draw(&ctx, assets.get()); + gui->draw(ctx, *assets); } void Engine::processPostRunnables() { diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index fff98f3f..2108b46e 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -67,9 +67,7 @@ std::unique_ptr UiDocument::read( : scripting::create_doc_environment(penv, name); gui::UiXmlReader reader(env); - auto view = reader.readXML( - file.u8string(), xmldoc->getRoot() - ); + auto view = reader.readXML(file.u8string(), *xmldoc->getRoot()); view->setId("root"); uidocscript script {}; auto scriptFile = fs::path(file.u8string()+".lua"); diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 30659969..21111e18 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -124,7 +124,7 @@ std::shared_ptr Hud::createContentAccess() { }); InventoryBuilder builder; - builder.addGrid(8, itemsCount-1, glm::vec2(), 8, true, slotLayout); + builder.addGrid(8, itemsCount-1, glm::vec2(), glm::vec4(8, 8, 12, 8), true, slotLayout); auto view = builder.build(); view->bind(accessInventory, content); view->setMargin(glm::vec4()); @@ -137,7 +137,7 @@ std::shared_ptr Hud::createHotbar() { SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr); InventoryBuilder builder; - builder.addGrid(10, 10, glm::vec2(), 4, true, slotLayout); + builder.addGrid(10, 10, glm::vec2(), glm::vec4(4), true, slotLayout); auto view = builder.build(); view->setId("hud.hotbar"); view->setOrigin(glm::vec2(view->getSize().x/2, 0)); @@ -346,9 +346,9 @@ void Hud::update(bool visible) { element.getNode()->setVisible(visible); } - glm::vec2 invSize = contentAccessPanel->getSize(); + glm::vec2 caSize = contentAccessPanel->getSize(); contentAccessPanel->setVisible(inventoryView != nullptr && showContentPanel); - contentAccessPanel->setSize(glm::vec2(invSize.x, Window::height)); + contentAccessPanel->setSize(glm::vec2(caSize.x, Window::height)); contentAccess->setMinSize(glm::vec2(1, Window::height)); hotbarView->setVisible(visible && !(secondUI && !inventoryView)); diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp index 580ab54d..5594664a 100644 --- a/src/frontend/hud.hpp +++ b/src/frontend/hud.hpp @@ -95,16 +95,16 @@ class Hud : public util::ObjectsKeeper { /// @brief Inventories interaction agent (grabbed item) std::shared_ptr exchangeSlot; /// @brief Exchange slot inventory (1 slot only) - std::shared_ptr exchangeSlotInv = nullptr; + std::shared_ptr exchangeSlotInv; /// @brief List of all controlled hud elements std::vector elements; /// @brief Player inventory view - std::shared_ptr inventoryView = nullptr; + std::shared_ptr inventoryView; /// @brief Block inventory view - std::shared_ptr blockUI = nullptr; + std::shared_ptr blockUI; /// @brief Secondary inventory view - std::shared_ptr secondInvView = nullptr; + std::shared_ptr secondInvView; /// @brief Position of the block open glm::ivec3 blockPos {}; /// @brief Id of the block open (used to detect block destruction or replacement) @@ -114,9 +114,9 @@ class Hud : public util::ObjectsKeeper { /// @brief Provide cheat controllers to the debug panel bool allowDebugCheats = true; /// @brief UI element will be dynamicly positioned near to inventory or in screen center - std::shared_ptr secondUI = nullptr; + std::shared_ptr secondUI; - std::shared_ptr debugMinimap = nullptr; + std::shared_ptr debugMinimap; std::unique_ptr debugImgWorldGen; diff --git a/src/graphics/core/Batch2D.cpp b/src/graphics/core/Batch2D.cpp index c4c67db2..b7ccf5ff 100644 --- a/src/graphics/core/Batch2D.cpp +++ b/src/graphics/core/Batch2D.cpp @@ -261,6 +261,24 @@ void Batch2D::rect( vertex(x+w, y+h, u+tx, v, r,g,b,a); } +void Batch2D::parallelogram( + float x, float y, float w, float h, float skew, + float u, float v, float tx, float ty, + float r, float g, float b, float a +){ + if (index + 6*B2D_VERTEX_SIZE >= capacity) { + flush(); + } + setPrimitive(DrawPrimitive::triangle); + vertex(x-skew*w, y, u, v+ty, r,g,b,a); + vertex(x+(1+skew)*w, y+h, u+tx, v, r,g,b,a); + vertex(x+skew*w, y+h, u, v, r,g,b,a); + + vertex(x-skew*w, y, u, v+ty, r,g,b,a); + vertex(x+w-skew*w, y, u+tx, v+ty, r,g,b,a); + vertex(x+(1+skew)*w, y+h, u+tx, v, r,g,b,a); +} + void Batch2D::rect( float x, float y, float w, float h, float r0, float g0, float b0, @@ -336,6 +354,22 @@ void Batch2D::sprite(float x, float y, float w, float h, int atlasRes, int index rect(x, y, w, h, u, v, scale, scale, tint.r, tint.g, tint.b, tint.a); } +void Batch2D::sprite( + float x, + float y, + float w, + float h, + float skew, + int atlasRes, + int index, + glm::vec4 tint +) { + float scale = 1.0f / (float)atlasRes; + float u = (index % atlasRes) * scale; + float v = 1.0f - ((index / atlasRes) * scale) - scale; + parallelogram(x, y, w, h, skew, u, v, scale, scale, tint.r, tint.g, tint.b, tint.a); +} + void Batch2D::flush() { if (index == 0) return; diff --git a/src/graphics/core/Batch2D.hpp b/src/graphics/core/Batch2D.hpp index 2877f5bd..6bfdb14d 100644 --- a/src/graphics/core/Batch2D.hpp +++ b/src/graphics/core/Batch2D.hpp @@ -45,6 +45,7 @@ public: void setRegion(UVRegion region); void sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint); void sprite(float x, float y, float w, float h, int atlasRes, int index, glm::vec4 tint); + void sprite(float x, float y, float w, float h, float skew, int atlasRes, int index, glm::vec4 tint); void point(float x, float y, float r, float g, float b, float a); inline void setColor(glm::vec4 color) { @@ -79,6 +80,12 @@ public: float r, float g, float b, float a ); + void parallelogram( + float x, float y, float w, float h, float skew, + float u, float v, float tx, float ty, + float r, float g, float b, float a + ); + void rect( float x, float y, float w, float h, float r0, float g0, float b0, diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index 9c40809f..2116fdd3 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -1,5 +1,6 @@ #include "Font.hpp" +#include #include #include "Texture.hpp" #include "Batch2D.hpp" @@ -52,17 +53,21 @@ static inline void draw_glyph( uint c, const glm::vec3& right, const glm::vec3& up, - float glyphInterval + float glyphInterval, + const FontStyle& style ) { - batch.sprite( - pos.x + offset.x * right.x, - pos.y + offset.y * right.y, - right.x / glyphInterval, - up.y, - 16, - c, - batch.getColor() - ); + for (int i = 0; i <= style.bold; i++) { + batch.sprite( + pos.x + (offset.x + i / (right.x/glyphInterval/2.0f)) * right.x, + pos.y + offset.y * right.y, + right.x / glyphInterval, + up.y, + -0.15f * style.italic, + 16, + c, + batch.getColor() * style.color + ); + } } static inline void draw_glyph( @@ -72,17 +77,20 @@ static inline void draw_glyph( uint c, const glm::vec3& right, const glm::vec3& up, - float glyphInterval + float glyphInterval, + const FontStyle& style ) { - batch.sprite( - pos + right * offset.x + up * offset.y, - up, right / glyphInterval, - 0.5f, - 0.5f, - 16, - c, - batch.getColor() - ); + for (int i = 0; i <= style.bold; i++) { + batch.sprite( + pos + right * (offset.x + i) + up * offset.y, + up, right / glyphInterval, + 0.5f, + 0.5f, + 16, + c, + batch.getColor() * style.color + ); + } } template @@ -93,14 +101,32 @@ static inline void draw_text( const glm::vec3& pos, const glm::vec3& right, const glm::vec3& up, - float glyphInterval + float interval, + const FontStylesScheme* styles, + size_t styleMapOffset ) { + static FontStylesScheme defStyles {{{}}, {0}}; + + if (styles == nullptr) { + styles = &defStyles; + } + uint page = 0; uint next = MAX_CODEPAGES; int x = 0; int y = 0; + bool hasLines = false; + do { - for (uint c : text){ + for (size_t i = 0; i < text.length(); i++) { + uint c = text[i]; + size_t styleIndex = styles->map.at( + std::min(styles->map.size() - 1, i + styleMapOffset) + ); + const FontStyle& style = styles->palette.at(styleIndex); + hasLines |= style.strikethrough; + hasLines |= style.underline; + if (!font.isPrintableChar(c)) { x++; continue; @@ -109,7 +135,7 @@ static inline void draw_text( if (charpage == page){ batch.texture(font.getPage(charpage)); draw_glyph( - batch, pos, glm::vec2(x, y), c, right, up, glyphInterval + batch, pos, glm::vec2(x, y), c, right, up, interval, style ); } else if (charpage > page && charpage < next){ @@ -121,6 +147,31 @@ static inline void draw_text( next = MAX_CODEPAGES; x = 0; } while (page < MAX_CODEPAGES); + + if (!hasLines) { + return; + } + batch.texture(font.getPage(0)); + for (size_t i = 0; i < text.length(); i++) { + uint c = text[i]; + size_t styleIndex = styles->map.at( + std::min(styles->map.size() - 1, i + styleMapOffset) + ); + const FontStyle& style = styles->palette.at(styleIndex); + FontStyle lineStyle = style; + lineStyle.bold = true; + if (style.strikethrough) { + draw_glyph( + batch, pos, glm::vec2(x, y), '-', right, up, interval, lineStyle + ); + } + if (style.underline) { + draw_glyph( + batch, pos, glm::vec2(x, y), '_', right, up, interval, lineStyle + ); + } + x++; + } } const Texture* Font::getPage(int charpage) const { @@ -135,20 +186,30 @@ const Texture* Font::getPage(int charpage) const { } void Font::draw( - Batch2D& batch, std::wstring_view text, int x, int y, float scale + Batch2D& batch, + std::wstring_view text, + int x, + int y, + const FontStylesScheme* styles, + size_t styleMapOffset, + float scale ) const { draw_text( *this, batch, text, glm::vec3(x, y, 0), glm::vec3(glyphInterval*scale, 0, 0), glm::vec3(0, lineHeight*scale, 0), - glyphInterval/static_cast(lineHeight) + glyphInterval/static_cast(lineHeight), + styles, + styleMapOffset ); } void Font::draw( Batch3D& batch, std::wstring_view text, + const FontStylesScheme* styles, + size_t styleMapOffset, const glm::vec3& pos, const glm::vec3& right, const glm::vec3& up @@ -157,6 +218,8 @@ void Font::draw( *this, batch, text, pos, right * static_cast(glyphInterval), up * static_cast(lineHeight), - glyphInterval/static_cast(lineHeight) + glyphInterval/static_cast(lineHeight), + styles, + styleMapOffset ); } diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index deb07534..07fe0532 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -11,10 +11,33 @@ class Batch2D; class Batch3D; class Camera; -enum class FontStyle { - none, - shadow, - outline +struct FontStyle { + bool bold = false; + bool italic = false; + bool strikethrough = false; + bool underline = false; + glm::vec4 color {1, 1, 1, 1}; + + FontStyle() = default; + + FontStyle( + bool bold, + bool italic, + bool strikethrough, + bool underline, + glm::vec4 color + ) + : bold(bold), + italic(italic), + strikethrough(strikethrough), + underline(underline), + color(std::move(color)) { + } +}; + +struct FontStylesScheme { + std::vector palette; + std::vector map; }; class Font { @@ -45,12 +68,22 @@ public: /// @brief Check if character is visible (non-whitespace) /// @param codepoint character unicode codepoint bool isPrintableChar(uint codepoint) const; - - void draw(Batch2D& batch, std::wstring_view text, int x, int y, float scale=1) const; + + void draw( + Batch2D& batch, + std::wstring_view text, + int x, + int y, + const FontStylesScheme* styles, + size_t styleMapOffset, + float scale = 1 + ) const; void draw( Batch3D& batch, std::wstring_view text, + const FontStylesScheme* styles, + size_t styleMapOffset, const glm::vec3& pos, const glm::vec3& right={1, 0, 0}, const glm::vec3& up={0, 1, 0} diff --git a/src/graphics/render/TextsRenderer.cpp b/src/graphics/render/TextsRenderer.cpp index ea9a69e4..32681ce5 100644 --- a/src/graphics/render/TextsRenderer.cpp +++ b/src/graphics/render/TextsRenderer.cpp @@ -65,12 +65,7 @@ void TextsRenderer::renderNote( xvec *= 1.0f + scale; yvec *= 1.0f + scale; } - if (preset.displayMode != NoteDisplayMode::PROJECTED) { - if (!frustum.isBoxVisible(pos - xvec * (width * 0.5f), - pos + xvec * (width * 0.5f))) { - return; - } - } else { + if (preset.displayMode == NoteDisplayMode::PROJECTED) { float scale = 1.0f; if (glm::abs(preset.perspective) > 0.0001f) { float scale2 = scale / @@ -99,12 +94,17 @@ void TextsRenderer::renderNote( pos = screenPos / screenPos.w; } + } else if (!frustum.isBoxVisible(pos - xvec * (width * 0.5f * preset.scale), + pos + xvec * (width * 0.5f * preset.scale))) { + return; } auto color = preset.color; batch.setColor(glm::vec4(color.r, color.g, color.b, color.a * opacity)); font.draw( batch, text, + nullptr, + 0, pos - xvec * (width * 0.5f) * preset.scale, xvec * preset.scale, yvec * preset.scale diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index 40b74a4c..38bc2257 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -197,18 +197,18 @@ void GUI::act(float delta, const Viewport& vp) { } } -void GUI::draw(const DrawContext* pctx, Assets* assets) { - auto& viewport = pctx->getViewport(); +void GUI::draw(const DrawContext& pctx, const Assets& assets) { + auto& viewport = pctx.getViewport(); glm::vec2 wsize = viewport.size(); menu->setPos((wsize - menu->getSize()) / 2.0f); uicamera->setFov(wsize.y); - auto uishader = assets->get("ui"); + auto uishader = assets.get("ui"); uishader->use(); uishader->uniformMatrix("u_projview", uicamera->getProjView()); - pctx->getBatch2D()->begin(); + pctx.getBatch2D()->begin(); container->draw(pctx, assets); } diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index b2b20bd0..c0dec649 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -94,7 +94,7 @@ namespace gui { /// @brief Draw all visible elements on main container /// @param pctx parent graphics context /// @param assets active assets storage - void draw(const DrawContext* pctx, Assets* assets); + void draw(const DrawContext& pctx, const Assets& assets); /// @brief Add element to the main container /// @param node UI element diff --git a/src/graphics/ui/elements/Button.cpp b/src/graphics/ui/elements/Button.cpp index b6a11232..dfdf864d 100644 --- a/src/graphics/ui/elements/Button.cpp +++ b/src/graphics/ui/elements/Button.cpp @@ -52,7 +52,7 @@ Button::Button( void Button::setText(std::wstring text) { if (label) { - label->setText(text); + label->setText(std::move(text)); } } @@ -77,9 +77,9 @@ void Button::refresh() { } } -void Button::drawBackground(const DrawContext* pctx, Assets*) { +void Button::drawBackground(const DrawContext& pctx, const Assets&) { glm::vec2 pos = calcPos(); - auto batch = pctx->getBatch2D(); + auto batch = pctx.getBatch2D(); batch->texture(nullptr); batch->setColor(calcColor()); batch->rect(pos.x, pos.y, size.x, size.y); diff --git a/src/graphics/ui/elements/Button.hpp b/src/graphics/ui/elements/Button.hpp index 61bfea03..39b23426 100644 --- a/src/graphics/ui/elements/Button.hpp +++ b/src/graphics/ui/elements/Button.hpp @@ -7,7 +7,7 @@ namespace gui { class Button : public Panel { protected: - std::shared_ptr