From 3deb7ff83058919b7c8dbecd91faaba6a2a36db5 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 26 Jul 2024 12:45:44 +0300 Subject: [PATCH 01/12] fix: delta time plotter is interactive --- src/frontend/hud.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 21dbc2c7..e43c4f6b 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -175,6 +175,7 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player) auto dplotter = std::make_shared(350, 250, 2000, 16); dplotter->setGravity(Gravity::bottom_right); + dplotter->setInteractive(false); add(HudElement(hud_element_mode::permanent, nullptr, dplotter, true)); } From 64ccf2a532316c2bca3d16e83dc44692749d19f7 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 26 Jul 2024 13:40:13 +0300 Subject: [PATCH 02/12] fix: thrid-person camera xray --- src/logic/PlayerController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 91801d79..938edcb1 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -169,13 +169,13 @@ void CameraControl::update(const PlayerInput& input, float delta, Chunks* chunks if (player->currentCamera == spCamera) { spCamera->position = chunks->rayCastToObstacle( - camera->position, camera->front, 3.0f) - 0.2f * camera->front; + camera->position, camera->front, 3.0f) - 0.4f * camera->front; spCamera->dir = -camera->dir; spCamera->front = -camera->front; } else if (player->currentCamera == tpCamera) { tpCamera->position = chunks->rayCastToObstacle( - camera->position, -camera->front, 3.0f) + 0.2f * camera->front; + camera->position, -camera->front, 3.0f) + 0.4f * camera->front; tpCamera->dir = camera->dir; tpCamera->front = camera->front; } From adafc94fa1166f2c1798b8e42fa7d557ca02dc9a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 27 Jul 2024 13:23:35 +0300 Subject: [PATCH 03/12] add block.compose_state(...), block.decompose_state(...) --- doc/en/scripting/builtins/libblock.md | 7 +++++++ doc/ru/scripting/builtins/libblock.md | 8 +++++++- src/logic/scripting/lua/libblock.cpp | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/en/scripting/builtins/libblock.md b/doc/en/scripting/builtins/libblock.md index 9516524c..6346f9d2 100644 --- a/doc/en/scripting/builtins/libblock.md +++ b/doc/en/scripting/builtins/libblock.md @@ -14,6 +14,7 @@ block.material(blockid: int) -> str block.caption(blockid: int) -> str -- Returns integer ID by block position +-- If the chunk at the specified coordinates is not loaded, returns -1. block.get(x: int, y: int, z: int) -> int -- Returns block state (rotation + additional information) as an integer. @@ -31,6 +32,12 @@ block.place(x: int, y: int, z: int, id: int, states: int, [optional] playerid: i -- Breaks a block at the given coordinates on behalf of the player, triggering the on_broken event. -- playerid is optional block.destruct(x: int, y: int, z: int, playerid: int) + +-- Compose the complete state as an integer +block.compose_state(rotation: int, segment: int, userbits: int) -> int + +-- Decompose the complete state into: rotation, segment, user bits +block.decompose_state(state: int) -> int, int, int ``` > [!WARNING] diff --git a/doc/ru/scripting/builtins/libblock.md b/doc/ru/scripting/builtins/libblock.md index 55de7aeb..c89cc5c5 100644 --- a/doc/ru/scripting/builtins/libblock.md +++ b/doc/ru/scripting/builtins/libblock.md @@ -17,7 +17,7 @@ block.caption(blockid: int) -> str -- Если чанк на указанных координатах не загружен, возвращает -1. block.get(x: int, y: int, z: int) -> int --- Возвращает состояние (поворот + доп. информация) в виде целого числа +-- Возвращает полное состояние (поворот + сегмент + доп. информация) в виде целого числа block.get_states(x: int, y: int, z: int) -> int -- Устанавливает блок с заданным числовым id и состоянием (0 - по-умолчанию) на заданных координатах. @@ -31,6 +31,12 @@ block.place(x: int, y: int, z: int, id: int, states: int, [optional] playerid: i -- Ломает блок на заданных координатах от лица игрока, вызывая событие on_broken. -- playerid не является обязательным block.destruct(x: int, y: int, z: int, playerid: int) + +-- Собирает полное состояние в виде целого числа +block.compose_state(rotation: int, segment: int, userbits: int) -> int + +-- Разбирает полное состояние на: вращение, сегмент, пользовательские биты +block.decompose_state(state: int) -> int, int, int ``` > [!WARNING] diff --git a/src/logic/scripting/lua/libblock.cpp b/src/logic/scripting/lua/libblock.cpp index 51182807..af2863b0 100644 --- a/src/logic/scripting/lua/libblock.cpp +++ b/src/logic/scripting/lua/libblock.cpp @@ -380,6 +380,23 @@ static int l_raycast(lua::State* L) { return 0; } +static int l_compose_state(lua::State* L) { + blockstate state {}; + state.rotation = lua::tointeger(L, 1); + state.segment = lua::tointeger(L, 2); + state.userbits = lua::tointeger(L, 3); + return lua::pushinteger(L, blockstate2int(state)); +} + +static int l_decompose_state(lua::State* L) { + auto stateInt = static_cast(lua::tointeger(L, 1)); + auto state = int2blockstate(stateInt); + lua::pushinteger(L, state.rotation); + lua::pushinteger(L, state.segment); + lua::pushinteger(L, state.userbits); + return 3; +} + const luaL_Reg blocklib [] = { {"index", lua::wrap}, {"name", lua::wrap}, @@ -411,5 +428,7 @@ const luaL_Reg blocklib [] = { {"place", lua::wrap}, {"destruct", lua::wrap}, {"raycast", lua::wrap}, + {"compose_state", lua::wrap}, + {"decompose_state", lua::wrap}, {NULL, NULL} }; From 26dcac013417f26f22cd01c9815e65e5452463b1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 27 Jul 2024 13:36:29 +0300 Subject: [PATCH 04/12] add doc/**/libplayer.md --- doc/en/scripting.md | 133 ++++++------------------- doc/en/scripting/builtins/libplayer.md | 70 +++++++++++++ doc/ru/scripting.md | 126 +++++------------------ doc/ru/scripting/builtins/libplayer.md | 70 +++++++++++++ 4 files changed, 198 insertions(+), 201 deletions(-) create mode 100644 doc/en/scripting/builtins/libplayer.md create mode 100644 doc/ru/scripting/builtins/libplayer.md diff --git a/doc/en/scripting.md b/doc/en/scripting.md index 2ae09e3b..5de576e5 100644 --- a/doc/en/scripting.md +++ b/doc/en/scripting.md @@ -13,6 +13,7 @@ Subsections: - [entities](scripting/builtins/libentities.md) - [cameras](scripting/builtins/libcameras.md) - [mat4](scripting/builtins/libmat4.md) + - [player](scripting/builtins/libplayer.md) - [quat](scripting/builtins/libquat.md) - [vec2, vec3, vec4](scripting/builtins/libvecn.md) - [Module core:bit_converter](scripting/modules/core_bit_converter.md) @@ -62,76 +63,55 @@ file.write(pack.data_file(PACK_ID, "example.txt"), text) For pack *containermod* will write text to the file `world:data/containermod/example.txt` -## *player* library +```python +pack.get_folder(packid: str) -> str +``` + +Returns installed content-pack folder. ```python -player.get_pos(playerid: int) -> number, number, number +pack.is_installed(packid: str) -> bool ``` -Returns x, y, z coordinates of the player +Check if the world has specified pack installed. ```python -player.set_pos(playerid: int, x: number, y: number, z: number) +pack.get_installed() -> strings array ``` -Set player position +Returns all installed content-pack ids. ```python -player.get_rot(playerid: int) -> number, number, number +pack.get_available() -> strings array ``` -Returns x, y, z of camera rotation (radians) +Returns the ids of all content packs available but not installed in the world. ```python -player.set_rot(playerid: int, x: number, y: number, z: number) +pack.get_base_packs() -> strings array ``` -Set camera rotation (radians) +Returns the id of all base packages (non-removeable) ```python -player.get_inventory(playerid: int) -> int, int +pack.get_info(packid: str) -> { + id: str, + title: str, + creator: str, + description: str, + version: str, + icon: str, + dependencies: optional strings array +} ``` -Returns player inventory ID and selected slot index (0-9) - -```python -player.is_flight() -> bool -player.set_flight(bool) -``` - -Getter and setter for player flight mode - -```python -player.is_noclip() -> bool -player.set_noclip(bool) -``` - -Getter and setter for player noclip mode (collisions disabled) - -``` python -player.set_spawnpoint(playerid: int, x: number, y: number, z: number) -player.get_spawnpoint(playerid: int) -> number, number, number -``` - -Point setter and getter added by player - -```python -player.get_selected_block(playerid: int) -> x,y,z -``` - -Returns position of the selected block or nil - -```python -player.get_selected_entity(playerid: int) -> int -``` - -Returns unique indentifier of the entity selected by player - -```python -player.get_entity(playerid: int) -> int -``` - -Returns unique identifier of the player entity +Returns information about the pack (not necessarily installed). +- icon - name of the preview texture (loading automatically) +- dependencies - strings following format `{lvl}{id}`, where lvl: + - `!` - required + - `?` - optional + - `~` - weak + for example `!teal` ## *world* library @@ -200,57 +180,6 @@ world.exists() -> bool Checks the existence of a world by name. -## *pack* library - -```python -pack.get_folder(packid: str) -> str -``` - -Returns installed content-pack folder. - -```python -pack.is_installed(packid: str) -> bool -``` - -Check if the world has specified pack installed. - -```python -pack.get_installed() -> strings array -``` - -Returns all installed content-pack ids. - -```python -pack.get_available() -> strings array -``` - -Returns the ids of all content packs available but not installed in the world. - -```python -pack.get_base_packs() -> strings array -``` - -Returns the id of all base packages (non-removeable) - -```python -pack.get_info(packid: str) -> { - id: str, - title: str, - creator: str, - description: str, - version: str, - icon: str, - dependencies: optional strings array -} -``` - -Returns information about the pack (not necessarily installed). -- icon - name of the preview texture (loading automatically) -- dependencies - strings following format `{lvl}{id}`, where lvl: - - `!` - required - - `?` - optional - - `~` - weak - for example `!teal` ## *gui* library @@ -282,7 +211,7 @@ gui.get_env(document: str) -> table Returns environment (global variables table) of the specified document. ```python -get_locales_info() -> table of tables where +gui.get_locales_info() -> table of tables where key - locale id following isolangcode_ISOCOUNTRYCODE format value - table { name: str # name of the locale in its language diff --git a/doc/en/scripting/builtins/libplayer.md b/doc/en/scripting/builtins/libplayer.md new file mode 100644 index 00000000..dda4f450 --- /dev/null +++ b/doc/en/scripting/builtins/libplayer.md @@ -0,0 +1,70 @@ +# *player* library + +```python +player.get_pos(playerid: int) -> number, number, number +``` + +Returns x, y, z coordinates of the player + +```python +player.set_pos(playerid: int, x: number, y: number, z: number) +``` + +Set player position + +```python +player.get_rot(playerid: int) -> number, number, number +``` + +Returns x, y, z of camera rotation (radians) + +```python +player.set_rot(playerid: int, x: number, y: number, z: number) +``` + +Set camera rotation (radians) + +```python +player.get_inventory(playerid: int) -> int, int +``` + +Returns player inventory ID and selected slot index (0-9) + +```python +player.is_flight() -> bool +player.set_flight(bool) +``` + +Getter and setter for player flight mode + +```python +player.is_noclip() -> bool +player.set_noclip(bool) +``` + +Getter and setter for player noclip mode (collisions disabled) + +``` python +player.set_spawnpoint(playerid: int, x: number, y: number, z: number) +player.get_spawnpoint(playerid: int) -> number, number, number +``` + +Point setter and getter added by player + +```python +player.get_selected_block(playerid: int) -> x,y,z +``` + +Returns position of the selected block or nil + +```python +player.get_selected_entity(playerid: int) -> int +``` + +Returns unique indentifier of the entity selected by player + +```python +player.get_entity(playerid: int) -> int +``` + +Returns unique identifier of the player entity diff --git a/doc/ru/scripting.md b/doc/ru/scripting.md index 88ef3b09..c2c124e4 100644 --- a/doc/ru/scripting.md +++ b/doc/ru/scripting.md @@ -13,6 +13,7 @@ - [entities](scripting/builtins/libentities.md) - [cameras](scripting/builtins/libcameras.md) - [mat4](scripting/builtins/libmat4.md) + - [player](scripting/builtins/libplayer.md) - [quat](scripting/builtins/libquat.md) - [vec2, vec3, vec4](scripting/builtins/libvecn.md) - [Модуль core:bit_converter](scripting/modules/core_bit_converter.md) @@ -58,76 +59,55 @@ file.write(pack.data_file(PACK_ID, "example.txt"), text) ``` Для пака *containermod* запишет текст в файл `world:data/containermod/example.txt` -## Библиотека *player* - ```python -player.get_pos(playerid: int) -> number, number, number +pack.get_folder(packid: str) -> str ``` -Возвращает x, y, z координаты игрока +Возвращает путь к папке установленного контент-пака. ```python -player.set_pos(playerid: int, x: number, y: number, z: number) +pack.is_installed(packid: str) -> bool ``` -Устанавливает x, y, z координаты игрока +Проверяет наличие контент-пака в мире ```python -player.get_rot(playerid: int) -> number, number, number +pack.get_installed() -> массив строк ``` -Возвращает x, y, z вращения камеры (в радианах) +Возращает id всех установленных в мире контент-паков. ```python -player.set_rot(playerid: int, x: number, y: number, z: number) +pack.get_available() -> массив строк ``` -Устанавливает x, y вращения камеры (в радианах) +Возвращает id всех доступных, но не установленных в мире контент-паков. ```python -player.get_inventory(playerid: int) -> int, int +pack.get_base_packs() -> массив строк ``` -Возвращает id инвентаря игрока и индекс выбранного слота (от 0 до 9) +Возвращает id всех базовых паков (неудаляемых) ```python -player.is_flight() -> bool -player.set_flight(bool) +pack.get_info(packid: str) -> { + id: str, + title: str, + creator: str, + description: str, + version: str, + icon: str, + dependencies: опциональный массив строк +} ``` -Геттер и сеттер режима полета - -```python -player.is_noclip() -> bool -player.set_noclip(bool) -``` - -Геттер и сеттер noclip режима (выключенная коллизия игрока) - -```python -player.set_spawnpoint(playerid: int, x: number, y: number, z: number) -player.get_spawnpoint(playerid: int) -> number, number, number -``` - -Сеттер и геттер точки спавна игрока - -```python -player.get_selected_block(playerid: int) -> x,y,z -``` - -Возвращает координаты выделенного блока, либо nil - -```python -player.get_selected_entity(playerid: int) -> int -``` - -Возвращает уникальный идентификатор сущности, на которую нацелен игрок - -```python -player.get_entity(playerid: int) -> int -``` - -Возвращает уникальный идентификатор сущности игрока +Возвращает информацию о паке (не обязательно установленном). +- icon - название текстуры предпросмотра (загружается автоматически) +- dependencies - строки в формате `{lvl}{id}`, где lvl: + - `!` - required + - `?` - optional + - `~` - weak + например `!teal` ## Библиотека *world* @@ -194,58 +174,6 @@ world.is_night() -> bool Проверяет является ли текущее время ночью. От 0.8(8 вечера) до 0.2(8 утра) -## Библиотека *pack* - -```python -pack.get_folder(packid: str) -> str -``` - -Возвращает путь к папке установленного контент-пака. - -```python -pack.is_installed(packid: str) -> bool -``` - -Проверяет наличие контент-пака в мире - -```python -pack.get_installed() -> массив строк -``` - -Возращает id всех установленных в мире контент-паков. - -```python -pack.get_available() -> массив строк -``` - -Возвращает id всех доступных, но не установленных в мире контент-паков. - -```python -pack.get_base_packs() -> массив строк -``` - -Возвращает id всех базовых паков (неудаляемых) - -```python -pack.get_info(packid: str) -> { - id: str, - title: str, - creator: str, - description: str, - version: str, - icon: str, - dependencies: опциональный массив строк -} -``` - -Возвращает информацию о паке (не обязательно установленном). -- icon - название текстуры предпросмотра (загружается автоматически) -- dependencies - строки в формате `{lvl}{id}`, где lvl: - - `!` - required - - `?` - optional - - `~` - weak - например `!teal` - ## Библиотека *gui* Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex: diff --git a/doc/ru/scripting/builtins/libplayer.md b/doc/ru/scripting/builtins/libplayer.md new file mode 100644 index 00000000..8b15d8df --- /dev/null +++ b/doc/ru/scripting/builtins/libplayer.md @@ -0,0 +1,70 @@ +# Библиотека *player* + +```python +player.get_pos(playerid: int) -> number, number, number +``` + +Возвращает x, y, z координаты игрока + +```python +player.set_pos(playerid: int, x: number, y: number, z: number) +``` + +Устанавливает x, y, z координаты игрока + +```python +player.get_rot(playerid: int) -> number, number, number +``` + +Возвращает x, y, z вращения камеры (в радианах) + +```python +player.set_rot(playerid: int, x: number, y: number, z: number) +``` + +Устанавливает x, y вращения камеры (в радианах) + +```python +player.get_inventory(playerid: int) -> int, int +``` + +Возвращает id инвентаря игрока и индекс выбранного слота (от 0 до 9) + +```python +player.is_flight() -> bool +player.set_flight(bool) +``` + +Геттер и сеттер режима полета + +```python +player.is_noclip() -> bool +player.set_noclip(bool) +``` + +Геттер и сеттер noclip режима (выключенная коллизия игрока) + +```python +player.set_spawnpoint(playerid: int, x: number, y: number, z: number) +player.get_spawnpoint(playerid: int) -> number, number, number +``` + +Сеттер и геттер точки спавна игрока + +```python +player.get_selected_block(playerid: int) -> x,y,z +``` + +Возвращает координаты выделенного блока, либо nil + +```python +player.get_selected_entity(playerid: int) -> int +``` + +Возвращает уникальный идентификатор сущности, на которую нацелен игрок + +```python +player.get_entity(playerid: int) -> int +``` + +Возвращает уникальный идентификатор сущности игрока From f485ba5e54d2a0315767aad0919bddc62cb6a10b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 27 Jul 2024 14:46:52 +0300 Subject: [PATCH 05/12] fix: invalid block segment was not removed on hover --- src/logic/PlayerController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logic/PlayerController.cpp b/src/logic/PlayerController.cpp index 938edcb1..3afd98a6 100644 --- a/src/logic/PlayerController.cpp +++ b/src/logic/PlayerController.cpp @@ -391,7 +391,7 @@ voxel* PlayerController::updateSelection(float maxDistance) { selection.position = chunks->seekOrigin( iend, indices->blocks.get(selection.vox.id), selectedState ); - auto origin = chunks->get(iend); + auto origin = chunks->get(selection.position); if (origin && origin->id != vox->id) { chunks->set(iend.x, iend.y, iend.z, 0, {}); return updateSelection(maxDistance); From 71e20ff805d9b713936ac1723f860cc6ba8e4497 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 27 Jul 2024 18:37:18 +0300 Subject: [PATCH 06/12] add block 'ambient-occlusion' property --- doc/en/block-properties.md | 4 + doc/ru/block-properties.md | 4 + res/content/base/blocks/wooden_door.json | 3 +- src/content/ContentLoader.cpp | 1 + src/graphics/render/BlocksRenderer.cpp | 150 ++++++++++++++++------- src/graphics/render/BlocksRenderer.hpp | 20 ++- src/graphics/render/ChunksRenderer.cpp | 1 + src/util/ThreadPool.hpp | 6 +- src/util/timeutil.hpp | 10 +- src/voxels/Block.hpp | 3 + 10 files changed, 149 insertions(+), 53 deletions(-) diff --git a/doc/en/block-properties.md b/doc/en/block-properties.md index 19cd01d1..1827a026 100644 --- a/doc/en/block-properties.md +++ b/doc/en/block-properties.md @@ -71,6 +71,10 @@ Vertical sky light ray ignores block if **true**. (used for water) Turns off block model shading +### *ambient-occlusion* (Vertex-based Ambient-Occlusion) + +Determines the presence of the vertex AO effect. Turned-on by default. + ## Physics ### *obstacle* diff --git a/doc/ru/block-properties.md b/doc/ru/block-properties.md index 495fd8ca..7e3a9768 100644 --- a/doc/ru/block-properties.md +++ b/doc/ru/block-properties.md @@ -74,6 +74,10 @@ Выключает освещение на модели блока. +### Вершинный Ambient-Occlusion - *ambient-occlusion* + +Определяет наличие эффекта вершинного AO. Включен по-умолчанию. + ## Физика ### Препятствие - *obstacle* diff --git a/res/content/base/blocks/wooden_door.json b/res/content/base/blocks/wooden_door.json index 9a1eb666..59d192b5 100644 --- a/res/content/base/blocks/wooden_door.json +++ b/res/content/base/blocks/wooden_door.json @@ -13,5 +13,6 @@ "size": [1, 2, 1], "rotation": "pane", "model": "aabb", - "hitbox": [0.0, 0.0, 0.8, 1.0, 2.0, 0.2] + "hitbox": [0.0, 0.0, 0.8, 1.0, 2.0, 0.2], + "ambient-occlusion": false } diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index 56480dfb..448754a2 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -217,6 +217,7 @@ void ContentLoader::loadBlock(Block& def, const std::string& name, const fs::pat root->flag("light-passing", def.lightPassing); root->flag("sky-light-passing", def.skyLightPassing); root->flag("shadeless", def.shadeless); + root->flag("ambient-occlusion", def.ambientOcclusion); root->flag("breakable", def.breakable); root->flag("selectable", def.selectable); root->flag("grounded", def.grounded); diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index ed20f7b3..e9b4f69c 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -104,7 +104,7 @@ void BlocksRenderer::face( index(0, 1, 3, 1, 2, 3); } -void BlocksRenderer::vertex( +void BlocksRenderer::vertexAO( const vec3& coord, float u, float v, const vec4& tint, @@ -117,7 +117,7 @@ void BlocksRenderer::vertex( vertex(coord, u, v, light * tint); } -void BlocksRenderer::face( +void BlocksRenderer::faceAO( const vec3& coord, const vec3& X, const vec3& Y, @@ -140,12 +140,12 @@ void BlocksRenderer::face( vec3 axisZ = glm::normalize(Z); vec4 tint(d); - vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisX, axisY, axisZ); - vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisX, axisY, axisZ); - vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ); - vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ); + vertexAO(coord + (-X - Y + Z) * s, region.u1, region.v1, tint, axisX, axisY, axisZ); + vertexAO(coord + ( X - Y + Z) * s, region.u2, region.v1, tint, axisX, axisY, axisZ); + vertexAO(coord + ( X + Y + Z) * s, region.u2, region.v2, tint, axisX, axisY, axisZ); + vertexAO(coord + (-X + Y + Z) * s, region.u1, region.v2, tint, axisX, axisY, axisZ); } else { - vec4 tint(1.0f); + glm::vec4 tint(1.0f); vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint); vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint); vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint); @@ -154,6 +154,33 @@ void BlocksRenderer::face( index(0, 1, 2, 0, 2, 3); } +void BlocksRenderer::face( + const vec3& coord, + const vec3& X, + const vec3& Y, + const vec3& Z, + const UVRegion& region, + vec4 tint, + bool lights +) { + if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) { + overflow = true; + return; + } + + float s = 0.5f; + if (lights) { + float d = glm::dot(glm::normalize(Z), SUN_VECTOR); + d = 0.8f + d * 0.2f; + tint *= d; + } + vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint); + vertex(coord + ( X - Y + Z) * s, region.u2, region.v1, tint); + vertex(coord + ( X + Y + Z) * s, region.u2, region.v2, tint); + vertex(coord + (-X + Y + Z) * s, region.u1, region.v2, tint); + index(0, 1, 2, 0, 2, 3); +} + void BlocksRenderer::tetragonicFace( const vec3& coord, const vec3& p1, const vec3& p2, const vec3& p3, const vec3& p4, @@ -231,7 +258,8 @@ void BlocksRenderer::blockAABB( const UVRegion(&texfaces)[6], const Block* block, ubyte rotation, - bool lights + bool lights, + bool ao ) { if (block->hitboxes.empty()) { return; @@ -256,18 +284,30 @@ void BlocksRenderer::blockAABB( } coord = vec3(icoord) - vec3(0.5f) + hitbox.center(); - face(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north - face(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south + if (ao) { + faceAO(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north + faceAO(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south - face(coord, X*size.x, -Z*size.z, Y*size.y, texfaces[3], lights); // top - face(coord, -X*size.x, -Z*size.z, -Y*size.y, texfaces[2], lights); // bottom + faceAO(coord, X*size.x, -Z*size.z, Y*size.y, texfaces[3], lights); // top + faceAO(coord, -X*size.x, -Z*size.z, -Y*size.y, texfaces[2], lights); // bottom - face(coord, -Z*size.z, Y*size.y, X*size.x, texfaces[1], lights); // west - face(coord, Z*size.z, Y*size.y, -X*size.x, texfaces[0], lights); // east + faceAO(coord, -Z*size.z, Y*size.y, X*size.x, texfaces[1], lights); // west + faceAO(coord, Z*size.z, Y*size.y, -X*size.x, texfaces[0], lights); // east + } else { + auto tint = pickLight(icoord); + face(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], tint, lights); // north + face(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], tint, lights); // south + + face(coord, X*size.x, -Z*size.z, Y*size.y, texfaces[3], tint, lights); // top + face(coord, -X*size.x, -Z*size.z, -Y*size.y, texfaces[2], tint, lights); // bottom + + face(coord, -Z*size.z, Y*size.y, X*size.x, texfaces[1], tint, lights); // west + face(coord, Z*size.z, Y*size.y, -X*size.x, texfaces[0], tint, lights); // east + } } void BlocksRenderer::blockCustomModel( - const ivec3& icoord, const Block* block, ubyte rotation, bool lights + const ivec3& icoord, const Block* block, ubyte rotation, bool lights, bool ao ) { vec3 X(1, 0, 0); vec3 Y(0, 1, 0); @@ -289,12 +329,12 @@ void BlocksRenderer::blockCustomModel( orient.transform(box); } vec3 center_coord = coord - vec3(0.5f) + box.center(); - face(center_coord, X * size.x, Y * size.y, Z * size.z, block->modelUVs[i * 6 + 5], lights); // north - face(center_coord, -X * size.x, Y * size.y, -Z * size.z, block->modelUVs[i * 6 + 4], lights); // south - face(center_coord, X * size.x, -Z * size.z, Y * size.y, block->modelUVs[i * 6 + 3], lights); // top - face(center_coord, -X * size.x, -Z * size.z, -Y * size.y, block->modelUVs[i * 6 + 2], lights); // bottom - face(center_coord, -Z * size.z, Y * size.y, X * size.x, block->modelUVs[i * 6 + 1], lights); // west - face(center_coord, Z * size.z, Y * size.y, -X * size.x, block->modelUVs[i * 6 + 0], lights); // east + faceAO(center_coord, X * size.x, Y * size.y, Z * size.z, block->modelUVs[i * 6 + 5], lights); // north + faceAO(center_coord, -X * size.x, Y * size.y, -Z * size.z, block->modelUVs[i * 6 + 4], lights); // south + faceAO(center_coord, X * size.x, -Z * size.z, Y * size.y, block->modelUVs[i * 6 + 3], lights); // top + faceAO(center_coord, -X * size.x, -Z * size.z, -Y * size.y, block->modelUVs[i * 6 + 2], lights); // bottom + faceAO(center_coord, -Z * size.z, Y * size.y, X * size.x, block->modelUVs[i * 6 + 1], lights); // west + faceAO(center_coord, Z * size.z, Y * size.y, -X * size.x, block->modelUVs[i * 6 + 0], lights); // east } for (size_t i = 0; i < block->modelExtraPoints.size()/4; i++) { @@ -314,7 +354,8 @@ void BlocksRenderer::blockCube( const UVRegion(&texfaces)[6], const Block* block, blockstate states, - bool lights + bool lights, + bool ao ) { ubyte group = block->drawGroup; @@ -330,23 +371,45 @@ void BlocksRenderer::blockCube( Z = orient.axisZ; } - if (isOpen(x+Z.x, y+Z.y, z+Z.z, group)) { - face(coord, X, Y, Z, texfaces[5], lights); - } - if (isOpen(x-Z.x, y-Z.y, z-Z.z, group)) { - face(coord, -X, Y, -Z, texfaces[4], lights); - } - if (isOpen(x+Y.x, y+Y.y, z+Y.z, group)) { - face(coord, X, -Z, Y, texfaces[3], lights); - } - if (isOpen(x-Y.x, y-Y.y, z-Y.z, group)) { - face(coord, X, Z, -Y, texfaces[2], lights); - } - if (isOpen(x+X.x, y+X.y, z+X.z, group)) { - face(coord, -Z, Y, X, texfaces[1], lights); - } - if (isOpen(x-X.x, y-X.y, z-X.z, group)) { - face(coord, Z, Y, -X, texfaces[0], lights); + if (ao) { + if (isOpen(x+Z.x, y+Z.y, z+Z.z, group)) { + faceAO(coord, X, Y, Z, texfaces[5], lights); + } + if (isOpen(x-Z.x, y-Z.y, z-Z.z, group)) { + faceAO(coord, -X, Y, -Z, texfaces[4], lights); + } + if (isOpen(x+Y.x, y+Y.y, z+Y.z, group)) { + faceAO(coord, X, -Z, Y, texfaces[3], lights); + } + if (isOpen(x-Y.x, y-Y.y, z-Y.z, group)) { + faceAO(coord, X, Z, -Y, texfaces[2], lights); + } + if (isOpen(x+X.x, y+X.y, z+X.z, group)) { + faceAO(coord, -Z, Y, X, texfaces[1], lights); + } + if (isOpen(x-X.x, y-X.y, z-X.z, group)) { + faceAO(coord, Z, Y, -X, texfaces[0], lights); + } + } else { + auto tint = pickLight({x, y, z}); + if (isOpen(x+Z.x, y+Z.y, z+Z.z, group)) { + face(coord, X, Y, Z, texfaces[5], tint, lights); + } + if (isOpen(x-Z.x, y-Z.y, z-Z.z, group)) { + face(coord, -X, Y, -Z, texfaces[4], tint, lights); + } + if (isOpen(x+Y.x, y+Y.y, z+Y.z, group)) { + face(coord, X, -Z, Y, texfaces[3], tint, lights); + } + if (isOpen(x-Y.x, y-Y.y, z-Y.z, group)) { + face(coord, X, Z, -Y, texfaces[2], tint, lights); + } + if (isOpen(x+X.x, y+X.y, z+X.z, group)) { + face(coord, -Z, Y, X, texfaces[1], tint, lights); + } + if (isOpen(x-X.x, y-X.y, z-X.z, group)) { + face(coord, Z, Y, -X, texfaces[0], tint, lights); + } } } @@ -440,7 +503,8 @@ void BlocksRenderer::render(const voxel* voxels) { int z = (i / CHUNK_D) % CHUNK_W; switch (def.model) { case BlockModel::block: - blockCube(x, y, z, texfaces, &def, vox.state, !def.shadeless); + blockCube(x, y, z, texfaces, &def, vox.state, !def.shadeless, + def.ambientOcclusion); break; case BlockModel::xsprite: { blockXSprite(x, y, z, vec3(1.0f), @@ -448,11 +512,13 @@ void BlocksRenderer::render(const voxel* voxels) { break; } case BlockModel::aabb: { - blockAABB(ivec3(x,y,z), texfaces, &def, vox.state.rotation, !def.shadeless); + blockAABB(ivec3(x,y,z), texfaces, &def, vox.state.rotation, + !def.shadeless, def.ambientOcclusion); break; } case BlockModel::custom: { - blockCustomModel(ivec3(x, y, z), &def, vox.state.rotation, !def.shadeless); + blockCustomModel(ivec3(x, y, z), &def, vox.state.rotation, + !def.shadeless, def.ambientOcclusion); break; } default: diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index e31fd163..d6cd6eb1 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -40,7 +40,7 @@ class BlocksRenderer { void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); void index(int a, int b, int c, int d, int e, int f); - void vertex( + void vertexAO( const glm::vec3& coord, float u, float v, const glm::vec4& brightness, const glm::vec3& axisX, @@ -58,6 +58,15 @@ class BlocksRenderer { const glm::vec4& tint ); void face( + const glm::vec3& coord, + const glm::vec3& X, + const glm::vec3& Y, + const glm::vec3& Z, + const UVRegion& region, + glm::vec4 tint, + bool lights + ); + void faceAO( const glm::vec3& coord, const glm::vec3& axisX, const glm::vec3& axisY, @@ -80,14 +89,16 @@ class BlocksRenderer { const UVRegion(&faces)[6], const Block* block, blockstate states, - bool lights + bool lights, + bool ao ); void blockAABB( const glm::ivec3& coord, const UVRegion(&faces)[6], const Block* block, ubyte rotation, - bool lights + bool lights, + bool ambientOcclusion ); void blockXSprite( int x, int y, int z, @@ -100,7 +111,8 @@ class BlocksRenderer { const glm::ivec3& icoord, const Block* block, ubyte rotation, - bool lights + bool lights, + bool ao ); bool isOpenForLight(int x, int y, int z) const; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index b46137af..0e7fe5cd 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -50,6 +50,7 @@ ChunksRenderer::ChunksRenderer( renderer = std::make_unique( RENDERER_CAPACITY, level->content, cache, settings ); + logger.info() << "created " << threadPool.getWorkersCount() << " workers"; } ChunksRenderer::~ChunksRenderer() { diff --git a/src/util/ThreadPool.hpp b/src/util/ThreadPool.hpp index 4fb1dff5..6b098b09 100644 --- a/src/util/ThreadPool.hpp +++ b/src/util/ThreadPool.hpp @@ -200,7 +200,7 @@ public: } } - void enqueueJob(std::shared_ptr job) { + void enqueueJob(const std::shared_ptr& job) { { std::lock_guard lock(jobsMutex); jobs.push(job); @@ -244,6 +244,10 @@ public: update(); } } + + uint getWorkersCount() const { + return threads.size(); + } }; } // namespace util diff --git a/src/util/timeutil.hpp b/src/util/timeutil.hpp index 3d117b73..75f72bfd 100644 --- a/src/util/timeutil.hpp +++ b/src/util/timeutil.hpp @@ -20,11 +20,11 @@ namespace timeutil { * ... * } */ - class ScopeLogTimer : public Timer{ - long long scopeid_; - public: - ScopeLogTimer(long long id); - ~ScopeLogTimer(); + class ScopeLogTimer : public Timer { + long long scopeid_; + public: + ScopeLogTimer(long long id); + ~ScopeLogTimer(); }; inline constexpr float time_value(float hour, float minute, float second) { diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index ce83079d..5c0dcfaa 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -136,6 +136,9 @@ public: /// @brief Does block model have shading bool shadeless = false; + + /// @brief Does block model have vertex-based AO effect + bool ambientOcclusion = true; /// @brief Is the block a physical obstacle bool obstacle = true; From 3fee1072b7a205e1bdc4dcef567b29da5df9f611 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 27 Jul 2024 22:59:06 +0300 Subject: [PATCH 07/12] fix 'block' model lights with AO turned-off --- src/graphics/render/BlocksRenderer.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index e9b4f69c..b5ea8194 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -391,24 +391,23 @@ void BlocksRenderer::blockCube( faceAO(coord, Z, Y, -X, texfaces[0], lights); } } else { - auto tint = pickLight({x, y, z}); if (isOpen(x+Z.x, y+Z.y, z+Z.z, group)) { - face(coord, X, Y, Z, texfaces[5], tint, lights); + face(coord, X, Y, Z, texfaces[5], pickLight({x, y, z+1}), lights); } if (isOpen(x-Z.x, y-Z.y, z-Z.z, group)) { - face(coord, -X, Y, -Z, texfaces[4], tint, lights); + face(coord, -X, Y, -Z, texfaces[4], pickLight({x, y, z-1}), lights); } if (isOpen(x+Y.x, y+Y.y, z+Y.z, group)) { - face(coord, X, -Z, Y, texfaces[3], tint, lights); + face(coord, X, -Z, Y, texfaces[3], pickLight({x, y+1, z}), lights); } if (isOpen(x-Y.x, y-Y.y, z-Y.z, group)) { - face(coord, X, Z, -Y, texfaces[2], tint, lights); + face(coord, X, Z, -Y, texfaces[2], pickLight({x, y-1, z}), lights); } if (isOpen(x+X.x, y+X.y, z+X.z, group)) { - face(coord, -Z, Y, X, texfaces[1], tint, lights); + face(coord, -Z, Y, X, texfaces[1], pickLight({x+1, y, z}), lights); } if (isOpen(x-X.x, y-X.y, z-X.z, group)) { - face(coord, Z, Y, -X, texfaces[0], tint, lights); + face(coord, Z, Y, -X, texfaces[0], pickLight({x-1, y, z}), lights); } } } From 8ca12127db57ab9f7117c5280c3b892c59d65a8e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 28 Jul 2024 12:38:31 +0300 Subject: [PATCH 08/12] add 'change-on-release' trackbar property & fix mouseRelease event timing --- src/graphics/ui/GUI.cpp | 2 +- src/graphics/ui/elements/TrackBar.cpp | 15 ++++++++++++++- src/graphics/ui/elements/TrackBar.hpp | 4 ++++ src/graphics/ui/gui_xml.cpp | 3 +++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index 54c04476..13f32a38 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -131,7 +131,7 @@ void GUI::actMouse(float delta) { focus->defocus(); focus = nullptr; } - } else if (pressed) { + } else if (!Events::clicked(mousecode::BUTTON_1) && pressed) { pressed->mouseRelease(this, Events::cursor.x, Events::cursor.y); pressed = nullptr; } diff --git a/src/graphics/ui/elements/TrackBar.cpp b/src/graphics/ui/elements/TrackBar.cpp index e7bcc8d3..816b4ae8 100644 --- a/src/graphics/ui/elements/TrackBar.cpp +++ b/src/graphics/ui/elements/TrackBar.cpp @@ -60,11 +60,16 @@ void TrackBar::mouseMove(GUI*, int x, int) { value = (value < min) ? min : value; value = (int64_t)round(value / step) * step; - if (consumer) { + if (consumer && !changeOnRelease) { consumer(value); } } +void TrackBar::mouseRelease(GUI*, int, int) { + if (consumer && changeOnRelease) { + consumer(value); + } +} double TrackBar::getValue() const { return value; @@ -90,6 +95,10 @@ glm::vec4 TrackBar::getTrackColor() const { return trackColor; } +bool TrackBar::isChangeOnRelease() const { + return changeOnRelease; +} + void TrackBar::setValue(double x) { value = x; } @@ -113,3 +122,7 @@ void TrackBar::setTrackWidth(int width) { void TrackBar::setTrackColor(glm::vec4 color) { trackColor = color; } + +void TrackBar::setChangeOnRelease(bool flag) { + changeOnRelease = flag; +} diff --git a/src/graphics/ui/elements/TrackBar.hpp b/src/graphics/ui/elements/TrackBar.hpp index ec62f87f..9a9fcad1 100644 --- a/src/graphics/ui/elements/TrackBar.hpp +++ b/src/graphics/ui/elements/TrackBar.hpp @@ -14,6 +14,7 @@ namespace gui { double value; double step; int trackWidth; + bool changeOnRelease = false; public: TrackBar(double min, double max, @@ -26,6 +27,7 @@ namespace gui { virtual void setConsumer(doubleconsumer consumer); virtual void mouseMove(GUI*, int x, int y) override; + virtual void mouseRelease(GUI*, int x, int y) override; virtual double getValue() const; virtual double getMin() const; @@ -33,6 +35,7 @@ namespace gui { virtual double getStep() const; virtual int getTrackWidth() const; virtual glm::vec4 getTrackColor() const; + virtual bool isChangeOnRelease() const; virtual void setValue(double); virtual void setMin(double); @@ -40,6 +43,7 @@ namespace gui { virtual void setStep(double); virtual void setTrackWidth(int); virtual void setTrackColor(glm::vec4); + virtual void setChangeOnRelease(bool); }; } diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index 94a0522d..e4e8310b 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -416,6 +416,9 @@ static std::shared_ptr readTrackBar(UiXmlReader& reader, const xml::xmle if (element->has("track-color")) { bar->setTrackColor(element->attr("track-color").asColor()); } + if (element->has("change-on-release")) { + bar->setChangeOnRelease(element->attr("change-on-release").asBool()); + } return bar; } From 479046a268d902f011191b0726f943555d43a7a4 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 28 Jul 2024 12:46:31 +0300 Subject: [PATCH 09/12] update doc/*/xml-ui-layouts.md --- doc/en/xml-ui-layouts.md | 70 +++++++++++++++++++++------------------- doc/ru/xml-ui-layouts.md | 1 + 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md index cdd13aa3..b13fdf2f 100644 --- a/doc/en/xml-ui-layouts.md +++ b/doc/en/xml-ui-layouts.md @@ -27,50 +27,52 @@ Examples: # Common element attributes -- **id** - element identifier. Type: string. -- **pos** - element position. Type: 2D vector. -- **size** - element size. Type: 2D vector. -- **color** - element color. Type: RGBA color. -- **margin** - element margin. Type: 4D vector +- `id` - element identifier. Type: string. +- `pos` - element position. Type: 2D vector. +- `size` - element size. Type: 2D vector. +- `color` - element color. Type: RGBA color. +- `margin` - element margin. Type: 4D vector *left, top, right, bottom* -- **visible** - element visibility. Type: boolean (true/false) -- **position-func** - position supplier for an element (two numbers), called on every parent container size update or on element adding on a container. May be called before *on_hud_open* +- `visible` - element visibility. Type: boolean (true/false) +- `position-func` - position supplier for an element (two numbers), called on every parent container size update or on element adding on a container. May be called before *on_hud_open* + # Common *container* attributes Buttons and panels are also containers. -- **padding** - element padding. Type: 4D vector. +- `padding` - element padding. Type: 4D vector. *left, top, right, bottom* - **scrollable** - element scrollability. Works on panels only. Type: boolean + `scrollable` - element scrollability. Works on panels only. Type: boolean # Common *panel* attributes Buttons are also panels. -- **max-length** - maximal length of panel stretching before scrolling (if scrollable = true). Type: number +- `max-length` - maximal length of panel stretching before scrolling (if scrollable = true). Type: number # Common elements ## *button* Inner text is a button text. -- **text-align** - inner text alignment (*left/center/right*). Type: string. -- **onclick** - Lua function called on button press. +- `text-align` - inner text alignment (*left/center/right*). Type: string. +- `onclick` - Lua function called on button press. ## *image* -- **src** - name of an image stored in textures folder. Extension is not specified. Type: string. +- `src` - name of an image stored in textures folder. Extension is not specified. Type: string. Example: *gui/error* ## *trackbar* -- **min** - minimal value. Type: number. Default: 0 -- **max** - maximal value. Type: number. Default: 1 -- **value** - initial value. Type: number. Default: 0 -- **step** - track step size. Type: number: Default: 1 -- **track-width** track pointer width (in steps). Type: number. Default: 1 -- **consumer** - Lua function - new value consumer -- **supplier** - Lua function - value supplier +- `min` - minimal value. Type: number. Default: 0 +- `max` - maximal value. Type: number. Default: 1 +- `value` - initial value. Type: number. Default: 0 +- `step` - track step size. Type: number: Default: 1 +- `track-width` track pointer width (in steps). Type: number. Default: 1 +- `consumer` - Lua function - new value consumer +- `supplier` - Lua function - value supplier +- `change-on-release` - Call consumer on trackbar release only. Type: boolean. Default: false # Inventory elements @@ -84,21 +86,21 @@ Element is a container. Does not have specific attributes. ## *slot* Element must be in direct sub-element of *inventory*. -- **index** - inventory slot index (starting from 0). Type: integer -- **item-source** - content access panel behaviour (infinite source of an item). Type: boolean -- **sharefunc** - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments. -- **updatefunc** - Lua event called on slot content update.Inventory id and slot index passed as arguments. -- **onrightclick** - Lua event called on RMB click. Inventory id and slot index passed as arguments. +- `index` - inventory slot index (starting from 0). Type: integer +- `item-source` - content access panel behaviour (infinite source of an item). Type: boolean +- `sharefunc` - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments. +- `updatefunc` - Lua event called on slot content update.Inventory id and slot index passed as arguments. +- `onrightclick` - Lua event called on RMB click. Inventory id and slot index passed as arguments. ## *slots-grid* -- **start-index** - inventory slot index of the first slot. Type: integer -- **rows** - number of grid rows (unnecessary if *cols* and *count* specified). Type: integer -- **cols** - number of grid columns (unnecessary if *rows* and *count* specified). Type: integer -- **count** - total number of slots in grid (unnecessary if *rows* and *cols* specified). Type: integer -- **interval** - visual slots interval. Type: number -- **padding** - grid padding (not slots interval). Type: number. (*deprecated*) -- **sharefunc** - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments. -- **updatefunc** - Lua event called on slot content update.Inventory id and slot index passed as arguments. -- **onrightclick** - Lua event called on RMB click. Inventory id and slot index passed as arguments. +- `start-index` - inventory slot index of the first slot. Type: integer +- `rows` - number of grid rows (unnecessary if *cols* and *count* specified). Type: integer +- `cols` - number of grid columns (unnecessary if *rows* and *count* specified). Type: integer +- `count` - total number of slots in grid (unnecessary if *rows* and *cols* specified). Type: integer +- `interval` - visual slots interval. Type: number +- `padding` - grid padding (not slots interval). Type: number. (*deprecated*) +- `sharefunc` - Lua event called on LMB + Shift. Inventory id and slot index passed as arguments. +- `updatefunc` - Lua event called on slot content update.Inventory id and slot index passed as arguments. +- `onrightclick` - Lua event called on RMB click. Inventory id and slot index passed as arguments. diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md index 6707f93c..5d08b1cf 100644 --- a/doc/ru/xml-ui-layouts.md +++ b/doc/ru/xml-ui-layouts.md @@ -117,6 +117,7 @@ - `track-color` - цвет указателя при наведении курсора. Тип: RGBA цвет. - `consumer` - lua функция-приемник установленного значения - `supplier` - lua функция-поставщик значения +- `change-on-release` - Вызов функции-приемника (consumer) происходит только тогда, когда пользователь отпускает указатель. Тип: логический. По-умолчанию: false # Элементы инвентаря From 0e3bd4dcac2f12d75a23a18f8ba54b7d8da9437b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 28 Jul 2024 12:57:58 +0300 Subject: [PATCH 10/12] update english version on xml-ui-layouts.md --- doc/en/xml-ui-layouts.md | 68 +++++++++++++++++++++++++++++++++------- doc/ru/xml-ui-layouts.md | 6 ++-- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md index b13fdf2f..0368866b 100644 --- a/doc/en/xml-ui-layouts.md +++ b/doc/en/xml-ui-layouts.md @@ -6,24 +6,25 @@ See also [ui elements in scripting](scripting/ui.md). **2D vector** - pair of numbers separated with comma. Examples: -- "500,200" -- "0.4,53.01" -- "0,0" +- `"500,200"` +- `"0.4,53.01"` +- `"0,0"` **3D vector** - three numbers separated with comma. Examples: -- "60,30,53" -- "0.4,0.1,0.753" +- `"60,30,53"` +- `"0.4,0.1,0.753"` **4D vector** - four numbers separated with comma. -- "10,5,10,3" -- "0.1,0.5,0.0,0.0" +Examples: +- `"10,5,10,3"` +- `"0.1,0.5,0.0,0.0"` **RGBA color** - only HEX notation available Examples: -- "#FF8000" - opaque orange -- "#FFFFFF80" - semi-transparent white -- "#000000FF" - opaque black +- `"#FF8000"` - opaque orange +- `"#FFFFFF80"` - semi-transparent white +- `"#000000FF"` - opaque black # Common element attributes @@ -35,6 +36,19 @@ Examples: *left, top, right, bottom* - `visible` - element visibility. Type: boolean (true/false) - `position-func` - position supplier for an element (two numbers), called on every parent container size update or on element adding on a container. May be called before *on_hud_open* +- `size-func` - element size provider (two numbers), called when the size of the container in which the element is located changes, or when an element is added to the container. Can be called before on_hud_open is called. +- `onclick` - lua function called when an element is clicked. +- `ondoubleclick` - lua function called when you double click on an element. +- `tooltip` - tooltip text +- `tooltip-delay` - tooltip show-up delay +- `gravity` - automatic positioning of the element in the container. (Does not work in automatic containers like panel). Values: *top-left, top-center, top-right, center-left, center-center, center-right, bottom-left, bottom-center, bottom-right*. +- `z-index` - determines the order of elements, with a larger value it will overlap elements with a smaller one. +- `interactive` - if false, hovering over the element and all sub-elements will be ignored. + +# Template attributes + +- `if` with values ​​('', 'false', 'nil') the element will be ignored, including sub-elements. +- `ifnot` is the same as `if`, but with the opposite condition. # Common *container* attributes @@ -49,6 +63,8 @@ Buttons and panels are also containers. Buttons are also panels. - `max-length` - maximal length of panel stretching before scrolling (if scrollable = true). Type: number +- `orientation` - panel orientation: horizontal/vertical. + # Common elements ## *button* @@ -56,13 +72,42 @@ Buttons are also panels. Inner text is a button text. - `text-align` - inner text alignment (*left/center/right*). Type: string. -- `onclick` - Lua function called on button press. + +## *checkbox* + +- `checked` - defines the checked state. +- `supplier` - mark state supplier (called every frame). +- `consumer` - lua function-consumer of the state of the mark. + +## *label* + +- `valign` - vertical text alignment: top/center/bottom. +- `supplier` - text supplier (called every frame). +- `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"). ## *image* - `src` - name of an image stored in textures folder. Extension is not specified. Type: string. Example: *gui/error* + ## *textbox* + +Inner text - initially entered text + +- `placeholder` - placeholder text (used if the text field is empty) +- `supplier` - text supplier (called every frame) +- `consumer` - lua function that receives the entered text. Called only when input is complete +- `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") +- `editable` - determines whether the text can be edited. +- `error-color` - color when entering incorrect data (the text does not pass the validator check). Type: RGBA color. +- `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. + ## *trackbar* - `min` - minimal value. Type: number. Default: 0 @@ -70,6 +115,7 @@ Inner text is a button text. - `value` - initial value. Type: number. Default: 0 - `step` - track step size. Type: number: Default: 1 - `track-width` track pointer width (in steps). Type: number. Default: 1 +- `track-color` - the color of the pointer when hovering over the cursor. Type: RGBA color. - `consumer` - Lua function - new value consumer - `supplier` - Lua function - value supplier - `change-on-release` - Call consumer on trackbar release only. Type: boolean. Default: false diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md index 5d08b1cf..189b1a2e 100644 --- a/doc/ru/xml-ui-layouts.md +++ b/doc/ru/xml-ui-layouts.md @@ -79,7 +79,8 @@ - `checked` - определяет состояние отметки. - `supplier` - поставщик состояния отметки (вызывается каждый кадр) -- `consumer` - lua функция-приемник состояния отметки. Вызывается только при завершении ввода +- `consumer` - lua функция-приемник состояния отметки. + ## Метка - *label* - `valign` - вертикальное выравнивание текста: top/center/bottom @@ -96,7 +97,7 @@ Внутренний текст - изначально введенный текст -- `placeholder` - текст подстановки (используется текстовое поле пусто) +- `placeholder` - текст подстановки (используется если текстовое поле пусто) - `supplier` - поставщик текста (вызывается каждый кадр) - `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода - `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта. @@ -107,6 +108,7 @@ - `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен. - `onup` - lua функция вызываемая при нажатии стрелки вверх. - `ondown` - lua функция вызываемая при нажатии стрелки вниз. + ## Ползунок - *trackbar* - `min` - минимальное значение. Тип: число. По-умолчанию: 0 From f46e4a7989efc2b95cca6d8834b7d6222718338f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 28 Jul 2024 22:15:18 +0300 Subject: [PATCH 11/12] add trackbar 'sub-consumer' for value label refresh when 'change-on-release' --- res/layouts/pages/settings_display.xml.lua | 7 +++--- res/layouts/pages/settings_graphics.xml.lua | 7 +++--- res/layouts/templates/track_setting.xml | 3 ++- src/data/dynamic_fwd.hpp | 3 +++ src/graphics/ui/elements/TrackBar.cpp | 7 ++++++ src/graphics/ui/elements/TrackBar.hpp | 7 ++++-- src/graphics/ui/gui_xml.cpp | 22 +++++++++---------- src/logic/scripting/scripting_functional.cpp | 23 ++++++++++++++++++++ src/logic/scripting/scripting_functional.hpp | 6 +++++ 9 files changed, 65 insertions(+), 20 deletions(-) diff --git a/res/layouts/pages/settings_display.xml.lua b/res/layouts/pages/settings_display.xml.lua index e861deb3..6e64a7d6 100644 --- a/res/layouts/pages/settings_display.xml.lua +++ b/res/layouts/pages/settings_display.xml.lua @@ -1,7 +1,8 @@ -function create_setting(id, name, step, postfix, tooltip) +function create_setting(id, name, step, postfix, tooltip, changeonrelease) local info = core.get_setting_info(id) postfix = postfix or "" tooltip = tooltip or "" + changeonrelease = changeonrelease or "" document.root:add(gui.template("track_setting", { id=id, name=gui.str(name, "settings"), @@ -10,13 +11,13 @@ function create_setting(id, name, step, postfix, tooltip) max=info.max, step=step, postfix=postfix, - tooltip=tooltip + tooltip=tooltip, + changeonrelease=changeonrelease })) update_setting(core.get_setting(id), id, name, postfix) end function update_setting(x, id, name, postfix) - core.set_setting(id, x) -- updating label document[id..".L"].text = string.format( "%s: %s%s", diff --git a/res/layouts/pages/settings_graphics.xml.lua b/res/layouts/pages/settings_graphics.xml.lua index de00c87b..8a479a1c 100644 --- a/res/layouts/pages/settings_graphics.xml.lua +++ b/res/layouts/pages/settings_graphics.xml.lua @@ -1,7 +1,8 @@ -function create_setting(id, name, step, postfix, tooltip) +function create_setting(id, name, step, postfix, tooltip, changeonrelease) local info = core.get_setting_info(id) postfix = postfix or "" tooltip = tooltip or "" + changeonrelease = changeonrelease or "" document.root:add(gui.template("track_setting", { id=id, name=gui.str(name, "settings"), @@ -10,13 +11,13 @@ function create_setting(id, name, step, postfix, tooltip) max=info.max, step=step, postfix=postfix, - tooltip=tooltip + tooltip=tooltip, + changeonrelease=changeonrelease })) update_setting(core.get_setting(id), id, name, postfix) end function update_setting(x, id, name, postfix) - core.set_setting(id, x) -- updating label document[id..".L"].text = string.format( "%s: %s%s", diff --git a/res/layouts/templates/track_setting.xml b/res/layouts/templates/track_setting.xml index 82ee81c1..519ba334 100644 --- a/res/layouts/templates/track_setting.xml +++ b/res/layouts/templates/track_setting.xml @@ -2,5 +2,6 @@ + consumer='function(x) core.set_setting("%{id}", x) end' change-on-release='%{changeonrelease}' + sub-consumer='function(x) update_setting(x, "%{id}", "%{name}", "%{postfix}") end'/> diff --git a/src/data/dynamic_fwd.hpp b/src/data/dynamic_fwd.hpp index 1a398edd..6faff946 100644 --- a/src/data/dynamic_fwd.hpp +++ b/src/data/dynamic_fwd.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace dynamic { class Map; @@ -27,6 +28,8 @@ namespace dynamic { bool, integer_t >; + + using to_string_func = std::function; } #endif // DATA_DYNAMIC_FWD_HPP_ diff --git a/src/graphics/ui/elements/TrackBar.cpp b/src/graphics/ui/elements/TrackBar.cpp index 816b4ae8..ab90b763 100644 --- a/src/graphics/ui/elements/TrackBar.cpp +++ b/src/graphics/ui/elements/TrackBar.cpp @@ -50,6 +50,10 @@ void TrackBar::setConsumer(doubleconsumer consumer) { this->consumer = std::move(consumer); } +void TrackBar::setSubConsumer(doubleconsumer consumer) { + this->subconsumer = std::move(consumer); +} + void TrackBar::mouseMove(GUI*, int x, int) { glm::vec2 pos = calcPos(); value = x - trackWidth/2; @@ -63,6 +67,9 @@ void TrackBar::mouseMove(GUI*, int x, int) { if (consumer && !changeOnRelease) { consumer(value); } + if (subconsumer) { + subconsumer(value); + } } void TrackBar::mouseRelease(GUI*, int, int) { diff --git a/src/graphics/ui/elements/TrackBar.hpp b/src/graphics/ui/elements/TrackBar.hpp index 9a9fcad1..6e055e61 100644 --- a/src/graphics/ui/elements/TrackBar.hpp +++ b/src/graphics/ui/elements/TrackBar.hpp @@ -2,6 +2,7 @@ #define GRAPHICS_UI_ELEMENTS_TRACKBAR_HPP_ #include "UINode.hpp" +#include "../../../data/dynamic_fwd.hpp" namespace gui { class TrackBar : public UINode { @@ -9,6 +10,7 @@ namespace gui { glm::vec4 trackColor {1.0f, 1.0f, 1.0f, 0.4f}; doublesupplier supplier = nullptr; doubleconsumer consumer = nullptr; + doubleconsumer subconsumer = nullptr; double min; double max; double value; @@ -23,8 +25,9 @@ namespace gui { int trackWidth=12); virtual void draw(const DrawContext* pctx, Assets* assets) override; - virtual void setSupplier(doublesupplier supplier); - virtual void setConsumer(doubleconsumer consumer); + virtual void setSupplier(doublesupplier); + virtual void setConsumer(doubleconsumer); + virtual void setSubConsumer(doubleconsumer); virtual void mouseMove(GUI*, int x, int y) override; virtual void mouseRelease(GUI*, int x, int y) override; diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index e4e8310b..297ee4ac 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -392,26 +392,26 @@ static std::shared_ptr readImage(UiXmlReader& reader, const xml::xmlelem } static std::shared_ptr readTrackBar(UiXmlReader& reader, const xml::xmlelement& element) { - float min = element->attr("min", "0.0").asFloat(); - float max = element->attr("max", "1.0").asFloat(); + const auto& env = reader.getEnvironment(); + const auto& file = reader.getFilename(); + float minv = element->attr("min", "0.0").asFloat(); + float maxv = element->attr("max", "1.0").asFloat(); float def = element->attr("value", "0.0").asFloat(); float step = element->attr("step", "1.0").asFloat(); int trackWidth = element->attr("track-width", "12").asInt(); - auto bar = std::make_shared(min, max, def, step, trackWidth); + auto bar = std::make_shared(minv, maxv, def, step, trackWidth); _readUINode(reader, element, *bar); if (element->has("consumer")) { bar->setConsumer(scripting::create_number_consumer( - reader.getEnvironment(), - element->attr("consumer").getText(), - reader.getFilename() - )); + env, element->attr("consumer").getText(), file)); + } + if (element->has("sub-consumer")) { + bar->setSubConsumer(scripting::create_number_consumer( + env, element->attr("sub-consumer").getText(), file)); } if (element->has("supplier")) { bar->setSupplier(scripting::create_number_supplier( - reader.getEnvironment(), - element->attr("supplier").getText(), - reader.getFilename() - )); + env, element->attr("supplier").getText(), file)); } if (element->has("track-color")) { bar->setTrackColor(element->attr("track-color").asColor()); diff --git a/src/logic/scripting/scripting_functional.cpp b/src/logic/scripting/scripting_functional.cpp index b758f336..b3ad82af 100644 --- a/src/logic/scripting/scripting_functional.cpp +++ b/src/logic/scripting/scripting_functional.cpp @@ -2,6 +2,7 @@ #include "lua/lua_engine.hpp" #include "../../debug/Logger.hpp" +#include "../../coders/json.hpp" #include "../../util/stringutil.hpp" using namespace scripting; @@ -177,3 +178,25 @@ vec2supplier scripting::create_vec2_supplier( return glm::vec2(0, 0); }; } + +dynamic::to_string_func scripting::create_tostring( + const scriptenv& env, + const std::string& src, + const std::string& file +) { + auto L = lua::get_main_thread(); + try { + lua::loadbuffer(L, *env, src, file); + lua::call(L, 0, 1); + auto func = lua::create_lambda(L); + return [func](const dynamic::Value& value) { + auto result = func({value}); + return json::stringify(result, true, " "); + }; + } catch (const lua::luaerror& err) { + logger.error() << err.what(); + return [](const auto& value) { + return json::stringify(value, true, " "); + }; + } +} diff --git a/src/logic/scripting/scripting_functional.hpp b/src/logic/scripting/scripting_functional.hpp index 9b1cc715..01141262 100644 --- a/src/logic/scripting/scripting_functional.hpp +++ b/src/logic/scripting/scripting_functional.hpp @@ -72,6 +72,12 @@ namespace scripting { const std::string& src, const std::string& file="" ); + + dynamic::to_string_func create_tostring( + const scriptenv& env, + const std::string& src, + const std::string& file="" + ); } #endif // LOGIC_SCRIPTING_SCRIPTING_FUNCTIONAL_HPP_ From 84f863f2d998b10bd28ba8e19d28dc40049f46da Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 28 Jul 2024 22:19:54 +0300 Subject: [PATCH 12/12] update doc/*/xml-ui-layouts.md --- doc/en/xml-ui-layouts.md | 1 + doc/ru/xml-ui-layouts.md | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md index 0368866b..61451b80 100644 --- a/doc/en/xml-ui-layouts.md +++ b/doc/en/xml-ui-layouts.md @@ -117,6 +117,7 @@ Inner text - initially entered text - `track-width` track pointer width (in steps). Type: number. Default: 1 - `track-color` - the color of the pointer when hovering over the cursor. Type: RGBA color. - `consumer` - Lua function - new value consumer +- `sub-consumer` - Lua function that receives intermediate values ​​(use to update text when `change-on-release="true"`) - `supplier` - Lua function - value supplier - `change-on-release` - Call consumer on trackbar release only. Type: boolean. Default: false diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md index 189b1a2e..16007a2e 100644 --- a/doc/ru/xml-ui-layouts.md +++ b/doc/ru/xml-ui-layouts.md @@ -118,6 +118,7 @@ - `track-width` - ширина указателя (в пикселях). Тип: число. По-умолчанию: 12 - `track-color` - цвет указателя при наведении курсора. Тип: RGBA цвет. - `consumer` - lua функция-приемник установленного значения +- `sub-consumer` - lua функция-приемник промежуточных значений (используйте для обновления текста при `change-on-release="true"`) - `supplier` - lua функция-поставщик значения - `change-on-release` - Вызов функции-приемника (consumer) происходит только тогда, когда пользователь отпускает указатель. Тип: логический. По-умолчанию: false