Merge branch 'MihailRis:main' into main
This commit is contained in:
commit
ee147ec7bd
200
CHANGELOG.md
200
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:
|
Table of contents:
|
||||||
|
|
||||||
- [Added](#added)
|
- [Added](#added)
|
||||||
- [Functions](#functions)
|
- [Functions](#functions)
|
||||||
- [Changes](#changes)
|
|
||||||
- [Fixes](#fixes)
|
- [Fixes](#fixes)
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- particles
|
- 3dtext
|
||||||
- VEC3 models support
|
- blockwraps
|
||||||
- handhold item display
|
- network (http requests and sockets)
|
||||||
- rules
|
|
||||||
- events:
|
|
||||||
- on_block_broken (documented)
|
|
||||||
- on_block_placed (documented)
|
|
||||||
- on_block_interact
|
|
||||||
- libraries:
|
- libraries:
|
||||||
- gfx.particles
|
- base64
|
||||||
- utf8
|
- gfx.text3d
|
||||||
- rules
|
- gfx.blockwraps
|
||||||
- bindings:
|
- network
|
||||||
- player.destroy
|
- events:
|
||||||
- player.fast_interaction
|
- on_replaced
|
||||||
- water overlay
|
- on_block_replaced
|
||||||
- block models from OBJ or VEC3
|
- on_player_tick
|
||||||
- bicubic heightmaps interpolation method
|
- structures 'lowering' property
|
||||||
- unicode escapes support
|
- add 'hint' property to textbox
|
||||||
- fragments placements
|
- add 'taking' and 'placing' properties to slot and slotsgrid
|
||||||
- console commands:
|
- add 'scroll-step' property to container
|
||||||
- time.daycycle
|
- add 'line-numbers' and 'text-color' to textbox
|
||||||
- fragment.place
|
- modules:
|
||||||
- rule.list
|
- base:util
|
||||||
- rule.set
|
- uinode property 'id'
|
||||||
- text field 'subconsumer'
|
- block.materials table
|
||||||
- shader uniforms:
|
- block.properties table
|
||||||
- u_lightDir to main shader
|
- item.properties table
|
||||||
- u_dayTime to skybox shader
|
- add version to world info table
|
||||||
- block properties:
|
- add 'sizeSpread' particles property
|
||||||
- overlay-texture
|
- add user properties
|
||||||
- model-name
|
|
||||||
- item properties:
|
|
||||||
- model-name
|
|
||||||
- 'Open content folder' buttons
|
|
||||||
- 'Background framerate limit' setting
|
|
||||||
|
|
||||||
### Functions
|
### Functions
|
||||||
|
|
||||||
- core.open_folder
|
- player.is_infinite_items
|
||||||
- world.get_generator
|
- player.set_infinite_items
|
||||||
- world.is_open
|
- player.is_instant_destruction
|
||||||
- item.placing_block
|
- player.set_instant_destruction
|
||||||
- item.model_name
|
- player.get_name
|
||||||
- item.emission
|
- player.set_name
|
||||||
- entities.get_hitbox
|
- hud.open
|
||||||
- utf8.tobytes
|
- base64.encode
|
||||||
- utf8.tostring
|
- base64.decode
|
||||||
- utf8.length
|
- utf8.escape
|
||||||
- utf8.codepoint
|
- string.escape
|
||||||
- utf8.encode
|
- textbox:lineAt
|
||||||
- utf8.sub
|
- textbox:linePos
|
||||||
- utf8.upper
|
- network.get
|
||||||
- utf8.lower
|
- network.get_binary
|
||||||
- file.read_combined_object
|
- network.tcp_connect
|
||||||
- fragment:place
|
- network.tcp_open
|
||||||
- rules.create
|
- network.get_total_upload
|
||||||
- rules.listen
|
- network.get_total_download
|
||||||
- rules.unlisten
|
- gfx.text3d.show
|
||||||
- rules.get
|
- gfx.text3d.hide
|
||||||
- rules.set
|
- gfx.text3d.get_text
|
||||||
- rules.reset
|
- gfx.text3d.set_text
|
||||||
- input.set_enabled
|
- gfx.text3d.get_pos
|
||||||
- hud._is_content_access
|
- gfx.text3d.set_pos
|
||||||
- hud._set_content_access
|
- gfx.text3d.get_axis_x
|
||||||
- hud._set_debug_cheats
|
- gfx.text3d.set_axis_x
|
||||||
- gfx.particles.emit
|
- gfx.text3d.get_axis_y
|
||||||
- gfx.particles.stop
|
- gfx.text3d.set_axis_y
|
||||||
- gfx.particles.get_origin
|
- gfx.text3d.set_rotation
|
||||||
- gfx.particles.set_origin
|
- gfx.text3d.update_settings
|
||||||
- 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
|
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
|
|
||||||
- [fix fatal error on editing texbox not having any consumer](https://github.com/MihailRis/VoxelEngine-Cpp/commit/22fa082fc6299ffa3196d62c67e01b849c35b8eb)
|
- [fix translucent blocks render](https://github.com/MihailRis/VoxelEngine-Cpp/pull/370)
|
||||||
- [fix commands boolean type support](https://github.com/MihailRis/VoxelEngine-Cpp/commit/a50cb109c8e3ca0f7a591bf126f07aee36c962e6)
|
- [fix blocks selection with semi-transparent blocks](https://github.com/MihailRis/VoxelEngine-Cpp/commit/171cbb48d099032d7e78c51a46c374104f96f0d1)
|
||||||
- [fix potential null dereferences on incorrect block.* functions use](https://github.com/MihailRis/VoxelEngine-Cpp/commit/961773c9f9745c15eb8d697c1538ac8e21f24da3)
|
- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b)
|
||||||
- [fix: draw-group not copied](https://github.com/MihailRis/VoxelEngine-Cpp/commit/dc8bad2af67e70b0b2346f516028e5795f597737)
|
- [mip-mapping related fixes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/d9277e1b31714632bd7f5f601b8362a9e7cb8819)
|
||||||
- [fix: generator-providing pack may be removed](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6f2f365278eb1866c773890471b7269a5ef45305)
|
- [fix disabled slots display](https://github.com/MihailRis/VoxelEngine-Cpp/commit/e8ee3e04b1398a3ada8445591267525304410571)
|
||||||
- [fix colision check on block place](https://github.com/MihailRis/VoxelEngine-Cpp/commit/726ee8ad703bc57530b881450b8839aaec6b97c9)
|
- [fix attack](https://github.com/MihailRis/VoxelEngine-Cpp/commit/bc17abc8b3ee7ff9027f7e3c375ca0330bb8e7bc)
|
||||||
- [fix collision detection bug](https://github.com/MihailRis/VoxelEngine-Cpp/commit/7fcc34ba4cf14097dfda26054b028c5e8771d26c)
|
- [fix: commands repository not reset before world open](https://github.com/MihailRis/VoxelEngine-Cpp/commit/1a00a91b604399f3108aa995422d371e573e650b)
|
||||||
- [fix: blocks lighting bug fix](https://github.com/MihailRis/VoxelEngine-Cpp/commit/9d3e872f88de2648f8c0f2e4611b30f5ce8999cf)
|
- [fix stdlib.lua](https://github.com/MihailRis/VoxelEngine-Cpp/commit/6ec33ab98c78523eaececf40f113f2323d25a33a)
|
||||||
- [fix: inaccurate framerate limit on Windows](https://github.com/MihailRis/VoxelEngine-Cpp/commit/3f531bbf98da5ad751dce1220c5c5fdf35f86c92)
|
- [fix file.write_bytes](https://github.com/MihailRis/VoxelEngine-Cpp/commit/0fec17a8b69ac81255b77022f3af5addf8fcc8f8)
|
||||||
- [fix block.get_hitbox again](https://github.com/MihailRis/VoxelEngine-Cpp/commit/edad594101e5808ccf14e0edefedbe87cb8f983b)
|
- [fix World::nextInventoryId](https://github.com/MihailRis/VoxelEngine-Cpp/commit/371fdaedcef2c163edd226160f388068b2bf5e83)
|
||||||
- [fix string.replace](https://github.com/MihailRis/VoxelEngine-Cpp/commit/44fd5416a9a110a12f8b3f2d369e5638055b306e)
|
- [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)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
## Latest release
|
## Latest release
|
||||||
|
|
||||||
- [Download](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest) | [Скачать](https://github.com/MihailRis/VoxelEngine-Cpp/releases/latest)
|
- [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
|
## Build project in Linux
|
||||||
|
|
||||||
@ -62,6 +62,12 @@ If you use Wayland
|
|||||||
sudo pacman -S glfw-wayland glew glm libpng libvorbis openal luajit libcurl
|
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
|
### Build engine with CMake
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
# Documentation
|
# 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
|
## Sections
|
||||||
|
|
||||||
@ -14,9 +14,10 @@ Documentation for the engine of in-development version 0.25.
|
|||||||
- [Content-packs](content-packs.md)
|
- [Content-packs](content-packs.md)
|
||||||
- [Engine usage recommendations](engine-use-recommendations.md)
|
- [Engine usage recommendations](engine-use-recommendations.md)
|
||||||
- [Item properties](item-properties.md)
|
- [Item properties](item-properties.md)
|
||||||
|
- [Particles](particles.md)
|
||||||
- [Resources (resources.json)](resources.md)
|
- [Resources (resources.json)](resources.md)
|
||||||
- [Rigging](rigging.md)
|
- [Rigging](rigging.md)
|
||||||
- [Scripting](scripting.md)
|
- [Scripting](scripting.md)
|
||||||
|
- [Text styles](text-styles.md)
|
||||||
- [World generator engine](world-generator.md)
|
- [World generator engine](world-generator.md)
|
||||||
- [XML UI building](xml-ui-layouts.md)
|
- [XML UI building](xml-ui-layouts.md)
|
||||||
- [Particles](particles.md)
|
|
||||||
|
|||||||
@ -39,3 +39,25 @@ gui.get_locales_info() -> table of tables {
|
|||||||
```
|
```
|
||||||
|
|
||||||
Returns information about all loaded locales (res/texts/\*).
|
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.
|
||||||
|
|||||||
@ -39,7 +39,7 @@ The Socket class has the following methods:
|
|||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Sends a byte array
|
-- Sends a byte array
|
||||||
socket:send(table|ByteArray)
|
socket:send(table|ByteArray|str)
|
||||||
|
|
||||||
-- Reads the received data
|
-- Reads the received data
|
||||||
socket:recv(
|
socket:recv(
|
||||||
@ -59,6 +59,9 @@ socket:is_alive() --> bool
|
|||||||
|
|
||||||
-- Checks if the connection is present (using socket:send(...) is available).
|
-- Checks if the connection is present (using socket:send(...) is available).
|
||||||
socket:is_connected() --> bool
|
socket:is_connected() --> bool
|
||||||
|
|
||||||
|
-- Returns the address and port of the connection.
|
||||||
|
socket:get_address() --> str, int
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
@ -80,6 +83,9 @@ server:close()
|
|||||||
|
|
||||||
-- Checks if the TCP server exists and is open.
|
-- Checks if the TCP server exists and is open.
|
||||||
server:is_open() --> bool
|
server:is_open() --> bool
|
||||||
|
|
||||||
|
-- Returns the server port.
|
||||||
|
server:get_port() --> int
|
||||||
```
|
```
|
||||||
|
|
||||||
## Analytics
|
## Analytics
|
||||||
|
|||||||
@ -108,6 +108,12 @@ function on_block_placed(blockid, x, y, z, playerid)
|
|||||||
|
|
||||||
Called on block placed by player
|
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
|
```lua
|
||||||
function on_block_broken(blockid, x, y, z, playerid)
|
function on_block_broken(blockid, x, y, z, playerid)
|
||||||
```
|
```
|
||||||
|
|||||||
@ -32,7 +32,7 @@ document["worlds-panel"]:clear()
|
|||||||
|
|
||||||
Properties that apply to all elements:
|
Properties that apply to all elements:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ------------- | ------ | ---- | ----- | ------------------------------------------- |
|
| ------------- | ------ | ---- | ----- | ------------------------------------------- |
|
||||||
| id | string | yes | *no* | element id |
|
| id | string | yes | *no* | element id |
|
||||||
| pos | vec2 | yes | yes | element position inside a container |
|
| pos | vec2 | yes | yes | element position inside a container |
|
||||||
@ -61,7 +61,7 @@ Common element methods:
|
|||||||
Common methods for containers (elements: container, panel, button, pagebox):
|
Common methods for containers (elements: container, panel, button, pagebox):
|
||||||
|
|
||||||
| Method | Description |
|
| Method | Description |
|
||||||
| ------------------------------- | ------------------------------------------------------------------ |
|
| ------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||||
| clear() | clears content |
|
| clear() | clears content |
|
||||||
| add(xml) | adds an element, creating it using xml code. Example: `container:add("<image src='test'/>")` |
|
| add(xml) | adds an element, creating it using xml code. Example: `container:add("<image src='test'/>")` |
|
||||||
| setInterval(interval, callback) | assigns a function to be executed repeatedly at an interval specified in milliseconds |
|
| setInterval(interval, callback) | assigns a function to be executed repeatedly at an interval specified in milliseconds |
|
||||||
@ -70,7 +70,7 @@ Common methods for containers (elements: container, panel, button, pagebox):
|
|||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ----------- | ------ | ---- | ----- | ------------------------------------------------------------------------------------ |
|
| ----------- | ------ | ---- | ----- | ------------------------------------------------------------------------------------ |
|
||||||
| text | string | yes | yes | entered text or placeholder |
|
| text | string | yes | yes | entered text or placeholder |
|
||||||
| placeholder | string | yes | yes | placeholder (used if nothing has been entered) |
|
| 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") |
|
| textWrap | bool | yes | yes | automatic text wrapping (only with multiline: "true") |
|
||||||
| valid | bool | yes | no | is the entered text correct |
|
| valid | bool | yes | no | is the entered text correct |
|
||||||
| textColor | vec4 | yes | yes | text color |
|
| textColor | vec4 | yes | yes | text color |
|
||||||
|
| syntax | string | yes | yes | syntax highlighting ("lua" - Lua) |
|
||||||
|
| markup | string | yes | yes | text markup language ("md" - Markdown) |
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
@ -95,7 +97,7 @@ Methods:
|
|||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ---------- | ----- | ---- | ----- | --------------------- |
|
| ---------- | ----- | ---- | ----- | --------------------- |
|
||||||
| value | float | yes | yes | current value |
|
| value | float | yes | yes | current value |
|
||||||
| min | float | yes | yes | minimum value |
|
| min | float | yes | yes | minimum value |
|
||||||
@ -108,7 +110,7 @@ Properties:
|
|||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ----- | ------ | ---- | ----- | ------------ |
|
| ----- | ------ | ---- | ----- | ------------ |
|
||||||
| page | string | yes | yes | current page |
|
| page | string | yes | yes | current page |
|
||||||
|
|
||||||
@ -123,7 +125,7 @@ Methods:
|
|||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ------- | ---- | ---- | ----- | ----------- |
|
| ------- | ---- | ---- | ----- | ----------- |
|
||||||
| checked | bool | yes | yes | mark status |
|
| checked | bool | yes | yes | mark status |
|
||||||
|
|
||||||
@ -131,7 +133,7 @@ Properties:
|
|||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ----- | ------ | ---- | ----- | ------------ |
|
| ----- | ------ | ---- | ----- | ------------ |
|
||||||
| text | string | yes | yes | button text |
|
| text | string | yes | yes | button text |
|
||||||
|
|
||||||
@ -139,15 +141,16 @@ Properties:
|
|||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ----- | ------ | ---- | ----- | ----------- |
|
| ------ | ------ | ---- | ----- | -------------------------------------- |
|
||||||
| text | string | yes | yes | label text |
|
| text | string | yes | yes | label text |
|
||||||
|
| markup | string | yes | yes | text markup language ("md" - Markdown) |
|
||||||
|
|
||||||
## Image
|
## Image
|
||||||
|
|
||||||
Properties:
|
Properties:
|
||||||
|
|
||||||
| Title | Type | Read | Write | Description |
|
| Name | Type | Read | Write | Description |
|
||||||
| ----- | ------ | ---- | ----- | ------------ |
|
| ----- | ------ | ---- | ----- | ------------ |
|
||||||
| src | string | yes | yes | texture name |
|
| src | string | yes | yes | texture name |
|
||||||
|
|
||||||
@ -155,6 +158,6 @@ Properties:
|
|||||||
|
|
||||||
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 |
|
| inventory | int | yes | yes | id of the inventory to which the element is bound |
|
||||||
|
|||||||
21
doc/en/text-styles.md
Normal file
21
doc/en/text-styles.md
Normal file
@ -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__` | <ins>Underlined text</ins> |
|
||||||
|
| Strikethrough | `~~Strikethrough text~~` | ~~Strikethrough text~~ |
|
||||||
|
|
||||||
|
Styles can be combined. Example:
|
||||||
|
```md
|
||||||
|
***__Message__*** using *~~combed~~ combined* styles__~~.~~__
|
||||||
|
```
|
||||||
|
Output:
|
||||||
|
|
||||||
|
***<ins>Message</ins>*** using *~~combed~~ combined* styles<ins>~~.~~</ins>
|
||||||
@ -87,6 +87,7 @@ Inner text is a button text.
|
|||||||
- `autoresize` - automatic change of element size (default - false). Does not affect font size.
|
- `autoresize` - automatic change of element size (default - false). Does not affect font size.
|
||||||
- `multiline` - allows display of multiline text.
|
- `multiline` - allows display of multiline text.
|
||||||
- `text-wrap` - allows automatic text wrapping (works only with multiline: "true").
|
- `text-wrap` - allows automatic text wrapping (works only with multiline: "true").
|
||||||
|
- `markup` - text markup language ("md" - Markdown).
|
||||||
|
|
||||||
## *image*
|
## *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.
|
- `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.
|
- `onup` - lua function called when the up arrow is pressed.
|
||||||
- `ondown` - lua function called when the down 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*
|
## *trackbar*
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
- [Свойства блоков](block-properties.md)
|
||||||
- [Свойства предметов](item-properties.md)
|
- [Свойства предметов](item-properties.md)
|
||||||
- [Скриптинг](scripting.md)
|
- [Скриптинг](scripting.md)
|
||||||
|
- [Стили текста](text-styles.md)
|
||||||
- [Частицы](particles.md)
|
- [Частицы](particles.md)
|
||||||
|
|||||||
@ -36,3 +36,25 @@ gui.get_locales_info() -> таблица таблиц где
|
|||||||
```
|
```
|
||||||
|
|
||||||
Возвращает информацию о всех загруженных локалях (res/texts/\*).
|
Возвращает информацию о всех загруженных локалях (res/texts/\*).
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gui.clear_markup(
|
||||||
|
-- язык разметки ("md" - Markdown)
|
||||||
|
language: str,
|
||||||
|
-- текст с разметкой
|
||||||
|
text: str
|
||||||
|
) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Удаляет разметку из текста.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gui.escape_markup(
|
||||||
|
-- язык разметки ("md" - Markdown)
|
||||||
|
language: str,
|
||||||
|
-- текст с разметкой
|
||||||
|
text: str
|
||||||
|
) -> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Экранирует разметку в тексте.
|
||||||
|
|||||||
@ -39,7 +39,7 @@ network.tcp_connect(
|
|||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Отправляет массив байт
|
-- Отправляет массив байт
|
||||||
socket:send(table|ByteArray)
|
socket:send(table|ByteArray|str)
|
||||||
|
|
||||||
-- Читает полученные данные
|
-- Читает полученные данные
|
||||||
socket:recv(
|
socket:recv(
|
||||||
@ -59,6 +59,9 @@ socket:is_alive() --> bool
|
|||||||
|
|
||||||
-- Проверяет наличие соединения (доступно использование socket:send(...)).
|
-- Проверяет наличие соединения (доступно использование socket:send(...)).
|
||||||
socket:is_connected() --> bool
|
socket:is_connected() --> bool
|
||||||
|
|
||||||
|
-- Возвращает адрес и порт соединения.
|
||||||
|
socket:get_address() --> str, int
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
@ -80,6 +83,9 @@ server:close()
|
|||||||
|
|
||||||
-- Проверяет, существует и открыт ли TCP сервер.
|
-- Проверяет, существует и открыт ли TCP сервер.
|
||||||
server:is_open() --> bool
|
server:is_open() --> bool
|
||||||
|
|
||||||
|
-- Возвращает порт сервера.
|
||||||
|
server:get_port() --> int
|
||||||
```
|
```
|
||||||
|
|
||||||
## Аналитика
|
## Аналитика
|
||||||
|
|||||||
@ -108,6 +108,12 @@ function on_block_placed(blockid, x, y, z, playerid)
|
|||||||
|
|
||||||
Вызывается после установки блока игроком
|
Вызывается после установки блока игроком
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function on_block_replaced(blockid, x, y, z, playerid)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вызывается после замены блока игроком
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function on_block_broken(blockid, x, y, z, playerid)
|
function on_block_broken(blockid, x, y, z, playerid)
|
||||||
```
|
```
|
||||||
|
|||||||
@ -10,6 +10,12 @@ table.copy(t: table) -> table
|
|||||||
|
|
||||||
Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной.
|
Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
table.deep_copy(t: table) -> table
|
||||||
|
```
|
||||||
|
|
||||||
|
Функция глубокого копирования создает полную копию исходной таблицы, включая все её вложенные таблицы.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
table.count_pairs(t: table) -> integer
|
table.count_pairs(t: table) -> integer
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,93 +1,98 @@
|
|||||||
# Модуль core:bit_converter
|
# Модуль core:bit_converter
|
||||||
|
|
||||||
|
## Доступные порядки байтов
|
||||||
|
**LE (Little-Endian)**
|
||||||
|
**BE (Big-Endian)**
|
||||||
|
По умолчанию используется **LE**
|
||||||
|
|
||||||
## Конвертация значений в байты и обратно
|
## Конвертация значений в байты и обратно
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.string_to_bytes(string: str) -> table
|
function bit_converter.string_to_bytes(str: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует строку в байты
|
Конвертирует строку в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bool_to_byte(boolean: bool) -> integer
|
function bit_converter.bool_to_byte(bool: boolean) -> integer
|
||||||
```
|
```
|
||||||
Конвертирует логический булев в байт
|
Конвертирует логический булев в байт
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.single_to_bytes(number: single) -> table
|
function bit_converter.float32_to_bytes(float: number, [опционально] order: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует плавающее значение одинарной точности в байты
|
Конвертирует плавающее значение одинарной точности в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.double_to_bytes(number: double) -> table
|
function bit_converter.float64_to_bytes(float: number, [опционально] order: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует плавающее значение двойной точности в байты
|
Конвертирует плавающее значение двойной точности в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.uint16_to_bytes(integer: int) -> table
|
function bit_converter.uint16_to_bytes(int: integer, [опционально] order: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует беззнаковое 2-х байтовое целое число в байты
|
Конвертирует беззнаковое 2-х байтовое целое число в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.uint32_to_bytes(integer: int) -> table
|
function bit_converter.uint32_to_bytes(int: integer, [опционально] order: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует беззнаковое 4-х байтовое целое число в байты
|
Конвертирует беззнаковое 4-х байтовое целое число в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.int16_to_bytes(integer: int) -> table
|
function bit_converter.sint16_to_bytes(int: integer, [опционально] order: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует знаковое 2-х байтовое целое число в байты
|
Конвертирует знаковое 2-х байтовое целое число в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.int32_to_bytes(integer: int) -> table
|
function bit_converter.sint32_to_bytes(int: integer, [опционально] order: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует знаковое 4-х байтовое целое число в байты
|
Конвертирует знаковое 4-х байтовое целое число в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.int64_to_bytes(integer: int) -> table
|
function bit_converter.int64_to_bytes(int: integer, [опционально] order: string) -> table
|
||||||
```
|
```
|
||||||
Конвертирует знаковое 8-и байтовое целое число в байты
|
Конвертирует знаковое 8-и байтовое целое число в байты
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_string(table: bytes) -> string
|
function bit_converter.bytes_to_string(bytes: table) -> string
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в строку
|
Конвертирует массив байтов в строку
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.byte_to_bool(integer: byte) -> boolean
|
function bit_converter.byte_to_bool(byte: integer) -> boolean
|
||||||
```
|
```
|
||||||
Конвертирует байт в логическое булевое значение
|
Конвертирует байт в логическое булевое значение
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_single(table: bytes) -> number№
|
function bit_converter.bytes_to_float32(bytes: table|Bytearray, [опционально] order: string) -> number
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в плавающее число одинарной точности
|
Конвертирует массив байтов в плавающее число одинарной точности
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_double(table: bytes) -> number
|
function bit_converter.bytes_to_float64(bytes: table|Bytearray, [опционально] order: string) -> number
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в плавающее число двойной точности
|
Конвертирует массив байтов в плавающее число двойной точности
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_uint16(table: bytes) -> integer
|
function bit_converter.bytes_to_uint16(bytes: table|Bytearray, [опционально] order: string) -> integer
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в 2-х байтовое беззнаковое число
|
Конвертирует массив байтов в 2-х байтовое беззнаковое число
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_uint32(table: bytes) -> integer
|
function bit_converter.bytes_to_uint32(bytes: table|Bytearray, [опционально] order: string) -> integer
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в 4-х байтовое беззнаковое число
|
Конвертирует массив байтов в 4-х байтовое беззнаковое число
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_int16(table: bytes) -> integer
|
function bit_converter.bytes_to_sint16(bytes: table|Bytearray, [опционально] order: string) -> integer
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в 2-х байтовое знаковое число
|
Конвертирует массив байтов в 2-х байтовое знаковое число
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_int32(table: bytes) -> integer
|
function bit_converter.bytes_to_sint32(bytes: table|Bytearray, [опционально] order: string) -> integer
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в 4-х байтовое знаковое число
|
Конвертирует массив байтов в 4-х байтовое знаковое число
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function bit_converter.bytes_to_int64(table: bytes) -> integer
|
function bit_converter.bytes_to_int64(bytes: table|Bytearray, [опционально] order: string) -> integer
|
||||||
```
|
```
|
||||||
Конвертирует массив байтов в 8-х байтовое знаковое число
|
Конвертирует массив байтов в 8-х байтовое знаковое число
|
||||||
|
|||||||
@ -4,67 +4,78 @@
|
|||||||
### Хранит в себе массив байтов и позволяет легко получать или добавлять разные значения
|
### Хранит в себе массив байтов и позволяет легко получать или добавлять разные значения
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer(bytes)
|
function data_buffer(
|
||||||
|
[опционально] bytes: table,
|
||||||
|
[опционально] order: string,
|
||||||
|
[опционально] useBytearray: boolean
|
||||||
|
)
|
||||||
```
|
```
|
||||||
Создаёт новый экземпляр data_buffer (параметр bytes необязательный)
|
Создаёт новый экземпляр **data_buffer**.
|
||||||
|
Если **useBytearray** равен **true**, то байты буффера будут хранится ввиде **Bytearray**. Это может снизить производительность, но также и уменьшить размер буффера в памяти
|
||||||
|
|
||||||
```lua
|
```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
|
```lua
|
||||||
function data_buffer:put_bytes(table: bytes)
|
function data_buffer:put_bytes(bytes: table|Bytearray)
|
||||||
```
|
```
|
||||||
Записывает байты в буффер
|
Записывает байты в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_string(string: str)
|
function data_buffer:put_string(str: string)
|
||||||
```
|
```
|
||||||
Конвертирует строку в байты и записывает их в буффер
|
Конвертирует строку в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_bool(boolean: bool)
|
function data_buffer:put_bool(bool: boolean)
|
||||||
```
|
```
|
||||||
Конвертирует булевое значение в байт и записывает его в буффер
|
Конвертирует булевое значение в байт и записывает его в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_single(number: single)
|
function data_buffer:put_float32(float: number)
|
||||||
```
|
```
|
||||||
Конвертирует плавающее число одинарной точности в байты и записывает их в буффер
|
Конвертирует плавающее число одинарной точности в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_double(number: double)
|
function data_buffer:put_float64(float: number)
|
||||||
```
|
```
|
||||||
Конвертирует плавающее число двойной точности в байты и записывает их в буффер
|
Конвертирует плавающее число двойной точности в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_uint16(integer: int)
|
function data_buffer:put_uint16(int: integer)
|
||||||
```
|
```
|
||||||
Конвертирует беззнаковое 2-х байтовое число в байты и записывает их в буффер
|
Конвертирует беззнаковое 2-х байтовое число в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_uint32(integer: int)
|
function data_buffer:put_uint32(int: integer)
|
||||||
```
|
```
|
||||||
Конвертирует беззнаковое 4-х байтовое число в байты и записывает их в буффер
|
Конвертирует беззнаковое 4-х байтовое число в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_int16(integer: int)
|
function data_buffer:put_sint16(int: integer)
|
||||||
```
|
```
|
||||||
Конвертирует знаковое 2-х байтовое число в байты и записывает их в буффер
|
Конвертирует знаковое 2-х байтовое число в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_int32(integer: int)
|
function data_buffer:put_sint32(int: integer)
|
||||||
```
|
```
|
||||||
Конвертирует знаковое 4-х байтовое число в байты и записывает их в буффер
|
Конвертирует знаковое 4-х байтовое число в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:put_int64(integer: int)
|
function data_buffer:put_int64(int: integer)
|
||||||
```
|
```
|
||||||
Конвертирует знаковое 8-и байтовое число в байты и записывает их в буффер
|
Конвертирует знаковое 8-и байтовое число в байты и записывает их в буффер
|
||||||
|
|
||||||
```lua
|
```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
|
zero = 0
|
||||||
uint16 = 1
|
uint16 = 1
|
||||||
uint32 = 2
|
uint32 = 2
|
||||||
int16 = 3
|
|
||||||
int32 = 4
|
|
||||||
int64 = 5
|
int64 = 5
|
||||||
double = 6
|
float64 = 6
|
||||||
|
sint16 = 7
|
||||||
|
sint32 = 8
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
@ -85,9 +96,9 @@ function data_buffer:get_byte() -> integer
|
|||||||
Возвращает следующий байт из буффера
|
Возвращает следующий байт из буффера
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:get_bytes(n) -> table
|
function data_buffer:get_bytes(n) -> table|Bytearray
|
||||||
```
|
```
|
||||||
Возвращает n следующих байтов, если n равен nil или не указан, то возвращается массив всех байтов
|
Возвращает **n** следующих байтов, если **n** равен **nil** или не указан, то возвращается массив всех байтов
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:get_string() -> string
|
function data_buffer:get_string() -> string
|
||||||
@ -100,12 +111,12 @@ function data_buffer:get_bool() -> boolean
|
|||||||
Читает следующий логический булев из буффера
|
Читает следующий логический булев из буффера
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:get_single() -> number
|
function data_buffer:get_float32() -> number
|
||||||
```
|
```
|
||||||
Читает следующее плавающее число одинарной точности из буффера
|
Читает следующее плавающее число одинарной точности из буффера
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:get_double() -> number
|
function data_buffer:get_float64() -> number
|
||||||
```
|
```
|
||||||
Читает следующее плавающее число двойной точности из буффера
|
Читает следующее плавающее число двойной точности из буффера
|
||||||
|
|
||||||
@ -120,12 +131,12 @@ function data_buffer:get_uint32() -> integer
|
|||||||
Читает следующее 4-х байтовое беззнаковое целое число из буффера
|
Читает следующее 4-х байтовое беззнаковое целое число из буффера
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:get_int16() -> integer
|
function data_buffer:get_sint16() -> integer
|
||||||
```
|
```
|
||||||
Читает следующее 2-х байтовое знаковое целое число из буффера
|
Читает следующее 2-х байтовое знаковое целое число из буффера
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
function data_buffer:get_int32() -> integer
|
function data_buffer:get_sint32() -> integer
|
||||||
```
|
```
|
||||||
Читает следующее 4-х байтовое знаковое целое число из буффера
|
Читает следующее 4-х байтовое знаковое целое число из буффера
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,8 @@ document["worlds-panel"]:clear()
|
|||||||
| textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") |
|
| textWrap | bool | да | да | автоматический перенос текста (только при multiline: "true") |
|
||||||
| valid | bool | да | нет | является ли введенный текст корректным |
|
| valid | bool | да | нет | является ли введенный текст корректным |
|
||||||
| textColor | vec4 | да | да | цвет текста |
|
| textColor | vec4 | да | да | цвет текста |
|
||||||
|
| syntax | string | да | да | подсветка синтаксиса ("lua" - Lua) |
|
||||||
|
| markup | string | да | да | язык разметки текста ("md" - Markdown) |
|
||||||
|
|
||||||
Методы:
|
Методы:
|
||||||
|
|
||||||
@ -140,8 +142,9 @@ document["worlds-panel"]:clear()
|
|||||||
Свойства:
|
Свойства:
|
||||||
|
|
||||||
| Название | Тип | Чтение | Запись | Описание |
|
| Название | Тип | Чтение | Запись | Описание |
|
||||||
| -------- | ------ | ------ | ------ | ----------- |
|
| -------- | ------ | ------ | ------ | -------------------------------------- |
|
||||||
| text | string | да | да | текст метки |
|
| text | string | да | да | текст метки |
|
||||||
|
| markup | string | да | да | язык разметки текста ("md" - Markdown) |
|
||||||
|
|
||||||
## Изображение (image)
|
## Изображение (image)
|
||||||
|
|
||||||
|
|||||||
21
doc/ru/text-styles.md
Normal file
21
doc/ru/text-styles.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Стили текста
|
||||||
|
|
||||||
|
Для разметки стилей текста используется собственный диалект Markdown.
|
||||||
|
Форматирование работает на UI элементах: label и textbox, если явно указано `markup="md"`.
|
||||||
|
|
||||||
|
## Стили
|
||||||
|
|
||||||
|
| Стиль | Пример | Вывод |
|
||||||
|
| ------------ | ------------------------- | ----------------------------- |
|
||||||
|
| Жирный | `**Жирный шрифт**` | **Жирный шрифт** |
|
||||||
|
| Курсив | `*Текст курсивом*` | *Текст курсивом* |
|
||||||
|
| Подчеркнутый | `__Подчеркнутый текст__` | <ins>Подчеркнутый текст</ins> |
|
||||||
|
| Зачеркнутый | `~~Зачеркнутый текст~~` | ~~Зачеркнутый текст~~ |
|
||||||
|
|
||||||
|
Стили могут объединяться. Пример:
|
||||||
|
```md
|
||||||
|
***__Сообщение__***, демонстрирующее *~~обедненные~~ объединенные* стили__~~.~~__
|
||||||
|
```
|
||||||
|
Вывод:
|
||||||
|
|
||||||
|
***<ins>Сообщение</ins>***, демонстрирующее *~~обедненные~~ объединенные* стили<ins>~~.~~</ins>
|
||||||
@ -89,6 +89,7 @@
|
|||||||
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
|
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
|
||||||
- `multiline` - разрешает отображение многострочного текста.
|
- `multiline` - разрешает отображение многострочного текста.
|
||||||
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
||||||
|
- `markup` - язык разметки текста ("md" - Markdown).
|
||||||
|
|
||||||
## Изображение - *image*
|
## Изображение - *image*
|
||||||
|
|
||||||
@ -113,6 +114,8 @@
|
|||||||
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
|
- `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен.
|
||||||
- `onup` - lua функция вызываемая при нажатии стрелки вверх.
|
- `onup` - lua функция вызываемая при нажатии стрелки вверх.
|
||||||
- `ondown` - lua функция вызываемая при нажатии стрелки вниз.
|
- `ondown` - lua функция вызываемая при нажатии стрелки вниз.
|
||||||
|
- `syntax` - подстветка синтаксиса ("lua" - Lua).
|
||||||
|
- `markup` - язык разметки текста ("md" - Markdown).
|
||||||
|
|
||||||
## Ползунок - *trackbar*
|
## Ползунок - *trackbar*
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
flake-utils.lib.eachDefaultSystem (system: {
|
flake-utils.lib.eachDefaultSystem (system: {
|
||||||
devShells.default = with nixpkgs.legacyPackages.${system}; mkShell {
|
devShells.default = with nixpkgs.legacyPackages.${system}; mkShell {
|
||||||
nativeBuildInputs = [ cmake pkg-config ];
|
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 ];
|
packages = [ glfw mesa freeglut entt ];
|
||||||
LD_LIBRARY_PATH = "${wayland}/lib:$LD_LIBRARY_PATH";
|
LD_LIBRARY_PATH = "${wayland}/lib:$LD_LIBRARY_PATH";
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "base",
|
"id": "base",
|
||||||
"title": "Base",
|
"title": "Base",
|
||||||
"version": "0.25",
|
"version": "0.26",
|
||||||
"description": "basic content package"
|
"description": "basic content package"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
multiline='true'
|
multiline='true'
|
||||||
size-func="gui.get_viewport()[1],40"
|
size-func="gui.get_viewport()[1],40"
|
||||||
gravity="bottom-left"
|
gravity="bottom-left"
|
||||||
|
markup="md"
|
||||||
></textbox>
|
></textbox>
|
||||||
</container>
|
</container>
|
||||||
<container id="editorContainer" pos="0,60" color="#00000080"
|
<container id="editorContainer" pos="0,60" color="#00000080"
|
||||||
@ -32,10 +33,9 @@
|
|||||||
autoresize='true'
|
autoresize='true'
|
||||||
margin='0'
|
margin='0'
|
||||||
padding='5'
|
padding='5'
|
||||||
editable='false'
|
|
||||||
multiline='true'
|
multiline='true'
|
||||||
line-numbers='true'
|
line-numbers='true'
|
||||||
text-color="#FFFFFFA0"
|
syntax='lua'
|
||||||
size-func="gui.get_viewport()[1]-350,40"
|
size-func="gui.get_viewport()[1]-350,40"
|
||||||
gravity="top-left"
|
gravity="top-left"
|
||||||
text-wrap='false'
|
text-wrap='false'
|
||||||
@ -55,6 +55,7 @@
|
|||||||
<textbox id='prompt'
|
<textbox id='prompt'
|
||||||
consumer='submit'
|
consumer='submit'
|
||||||
margin='0'
|
margin='0'
|
||||||
|
markup="md"
|
||||||
gravity='bottom-left'
|
gravity='bottom-left'
|
||||||
size-func="gui.get_viewport()[1],40"
|
size-func="gui.get_viewport()[1],40"
|
||||||
onup="on_history_up()"
|
onup="on_history_up()"
|
||||||
|
|||||||
@ -12,17 +12,57 @@ local MIN_INT32 = -2147483648
|
|||||||
local MAX_INT64 = 9223372036854775807
|
local MAX_INT64 = 9223372036854775807
|
||||||
local MIN_INT64 = -9223372036854775808
|
local MIN_INT64 = -9223372036854775808
|
||||||
|
|
||||||
local function intToByte(num)
|
local function maskHighBytes(num)
|
||||||
return bit.band(num, 0xFF)
|
return bit.band(num, 0xFF)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function reverse(tab)
|
local function reverse(tbl)
|
||||||
for i = 1, math.floor(#tab, 2), 1 do
|
for i=1, math.floor(#tbl / 2) do
|
||||||
tab[i], tab[#tab-i+1] = tab[#tab-i+1], tab[i]
|
local tmp = tbl[i]
|
||||||
|
tbl[i] = tbl[#tbl - i + 1]
|
||||||
|
tbl[#tbl - i + 1] = tmp
|
||||||
end
|
end
|
||||||
return tab
|
return tbl
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local orders = { "LE", "BE" }
|
||||||
|
|
||||||
|
local fromLEConvertors =
|
||||||
|
{
|
||||||
|
LE = function(bytes) return bytes end,
|
||||||
|
BE = function(bytes) return reverse(bytes) end
|
||||||
|
}
|
||||||
|
|
||||||
|
local toLEConvertors =
|
||||||
|
{
|
||||||
|
LE = function(bytes) return bytes end,
|
||||||
|
BE = function(bytes) return reverse(bytes) end
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_converter.default_order = "LE"
|
||||||
|
|
||||||
|
local function fromLE(bytes, orderTo)
|
||||||
|
if orderTo then
|
||||||
|
bit_converter.validate_order(orderTo)
|
||||||
|
return fromLEConvertors[orderTo](bytes)
|
||||||
|
else return bytes end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function toLE(bytes, orderFrom)
|
||||||
|
if orderFrom then
|
||||||
|
bit_converter.validate_order(orderFrom)
|
||||||
|
return toLEConvertors[orderFrom](bytes)
|
||||||
|
else return bytes end
|
||||||
|
end
|
||||||
|
|
||||||
|
function bit_converter.validate_order(order)
|
||||||
|
if not bit_converter.is_valid_order(order) then
|
||||||
|
error("invalid order: "..order)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function bit_converter.is_valid_order(order) return table.has(orders, order) end
|
||||||
|
|
||||||
function bit_converter.string_to_bytes(str)
|
function bit_converter.string_to_bytes(str)
|
||||||
local bytes = { }
|
local bytes = { }
|
||||||
|
|
||||||
@ -83,19 +123,12 @@ local function floatOrDoubleToBytes(val, opt)
|
|||||||
bytes[#bytes + 1] = math.floor(sign * 128 + val) % (2 ^ 8)
|
bytes[#bytes + 1] = math.floor(sign * 128 + val) % (2 ^ 8)
|
||||||
val = math.floor((sign * 128 + val) / (2 ^ 8))
|
val = math.floor((sign * 128 + val) / (2 ^ 8))
|
||||||
|
|
||||||
if not endianness then
|
|
||||||
reverse(bytes)
|
|
||||||
end
|
|
||||||
return bytes
|
return bytes
|
||||||
end
|
end
|
||||||
|
|
||||||
local function bytesToFloatOrDouble(bytes, opt)
|
local function bytesToFloatOrDouble(bytes, opt)
|
||||||
local n = (opt == 'd') and 8 or 4
|
local n = (opt == 'd') and 8 or 4
|
||||||
|
|
||||||
if not endianness then
|
|
||||||
reverse(bytes)
|
|
||||||
end
|
|
||||||
|
|
||||||
local sign = 1
|
local sign = 1
|
||||||
local mantissa = bytes[n - 1] % ((opt == 'd') and 16 or 128)
|
local mantissa = bytes[n - 1] % ((opt == 'd') and 16 or 128)
|
||||||
for i = n - 2, 1, -1 do
|
for i = n - 2, 1, -1 do
|
||||||
@ -117,80 +150,128 @@ end
|
|||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
function bit_converter.single_to_bytes(float)
|
function bit_converter.float32_to_bytes(float, order)
|
||||||
return floatOrDoubleToBytes(float, 'f')
|
return fromLE(floatOrDoubleToBytes(float, 'f'), order)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.double_to_bytes(double)
|
function bit_converter.float64_to_bytes(float, order)
|
||||||
return floatOrDoubleToBytes(double, 'd')
|
return fromLE(floatOrDoubleToBytes(float, 'd'), order)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.uint32_to_bytes(int)
|
function bit_converter.single_to_bytes(float, order)
|
||||||
|
on_deprecated_call("bit_converter.float_to_bytes", "bit_converter.float32_to_bytes")
|
||||||
|
return bit_converter.float32_to_bytes(bytes, order)
|
||||||
|
end
|
||||||
|
|
||||||
|
function bit_converter.double_to_bytes(double, order)
|
||||||
|
on_deprecated_call("bit_converter.double_to_bytes", "bit_converter.float64_to_bytes")
|
||||||
|
return bit_converter.float64_to_bytes(bytes, order)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function uint32ToBytes(int, order)
|
||||||
|
return fromLE({
|
||||||
|
maskHighBytes(bit.rshift(int, 24)),
|
||||||
|
maskHighBytes(bit.rshift(int, 16)),
|
||||||
|
maskHighBytes(bit.rshift(int, 8)),
|
||||||
|
maskHighBytes(int)
|
||||||
|
}, order)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function uint16ToBytes(int, order)
|
||||||
|
return fromLE({
|
||||||
|
maskHighBytes(bit.rshift(int, 8)),
|
||||||
|
maskHighBytes(int)
|
||||||
|
}, order)
|
||||||
|
end
|
||||||
|
|
||||||
|
function bit_converter.uint32_to_bytes(int, order)
|
||||||
if int > MAX_UINT32 or int < MIN_UINT32 then
|
if int > MAX_UINT32 or int < MIN_UINT32 then
|
||||||
error("invalid uint32")
|
error("invalid uint32")
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return uint32ToBytes(int, order)
|
||||||
intToByte(bit.rshift(int, 24)),
|
|
||||||
intToByte(bit.rshift(int, 16)),
|
|
||||||
intToByte(bit.rshift(int, 8)),
|
|
||||||
intToByte(int)
|
|
||||||
}
|
|
||||||
end
|
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
|
if int > MAX_UINT16 or int < MIN_UINT16 then
|
||||||
error("invalid uint16")
|
error("invalid uint16")
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return uint16ToBytes(int, order)
|
||||||
intToByte(bit.rshift(int, 8)),
|
|
||||||
intToByte(int)
|
|
||||||
}
|
|
||||||
end
|
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
|
if int > MAX_INT64 or int < MIN_INT64 then
|
||||||
error("invalid int64")
|
error("invalid int64")
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return fromLE({
|
||||||
intToByte(bit.rshift(int, 56)),
|
maskHighBytes(bit.rshift(int, 56)),
|
||||||
intToByte(bit.rshift(int, 48)),
|
maskHighBytes(bit.rshift(int, 48)),
|
||||||
intToByte(bit.rshift(int, 40)),
|
maskHighBytes(bit.rshift(int, 40)),
|
||||||
intToByte(bit.rshift(int, 32)),
|
maskHighBytes(bit.rshift(int, 32)),
|
||||||
intToByte(bit.rshift(int, 24)),
|
maskHighBytes(bit.rshift(int, 24)),
|
||||||
intToByte(bit.rshift(int, 16)),
|
maskHighBytes(bit.rshift(int, 16)),
|
||||||
intToByte(bit.rshift(int, 8)),
|
maskHighBytes(bit.rshift(int, 8)),
|
||||||
intToByte(int)
|
maskHighBytes(int)
|
||||||
}
|
}, order)
|
||||||
end
|
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
|
if int > MAX_INT32 or int < MIN_INT32 then
|
||||||
error("invalid int32")
|
error("invalid int32")
|
||||||
end
|
end
|
||||||
|
|
||||||
return bit_converter.uint32_to_bytes(int + MAX_INT32)
|
return uint32ToBytes(int + MAX_INT32, order)
|
||||||
end
|
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
|
if int > MAX_INT16 or int < MIN_INT16 then
|
||||||
error("invalid int16")
|
error("invalid int16")
|
||||||
end
|
end
|
||||||
|
|
||||||
return bit_converter.uint16_to_bytes(int + MAX_INT16)
|
return uint16ToBytes(int + MAX_INT16, order)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.bytes_to_single(bytes)
|
function bit_converter.sint32_to_bytes(int, order)
|
||||||
return bytesToFloatOrDouble(bytes, 'f')
|
if int > MAX_INT32 or int < MIN_INT32 then
|
||||||
|
error("invalid sint32")
|
||||||
|
end
|
||||||
|
|
||||||
|
return uint32ToBytes(int + MAX_UINT32 + 1, order)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.bytes_to_double(bytes)
|
function bit_converter.sint16_to_bytes(int, order)
|
||||||
return bytesToFloatOrDouble(bytes, 'd')
|
if int > MAX_INT16 or int < MIN_INT16 then
|
||||||
|
error("invalid sint16")
|
||||||
|
end
|
||||||
|
|
||||||
|
return uint16ToBytes(int + MAX_UINT16 + 1, order)
|
||||||
end
|
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 len = bit_converter.bytes_to_uint16({ bytes[1], bytes[2] })
|
||||||
|
|
||||||
local str = ""
|
local str = ""
|
||||||
@ -206,17 +287,13 @@ function bit_converter.byte_to_bool(byte)
|
|||||||
return byte ~= 0
|
return byte ~= 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.bytes_to_float(bytes)
|
function bit_converter.bytes_to_uint32(bytes, order)
|
||||||
if #bytes < 8 then
|
|
||||||
error("eof")
|
|
||||||
end
|
|
||||||
error("unsupported operation")
|
|
||||||
end
|
|
||||||
|
|
||||||
function bit_converter.bytes_to_uint32(bytes)
|
|
||||||
if #bytes < 4 then
|
if #bytes < 4 then
|
||||||
error("eof")
|
error("eof")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
bytes = toLE(bytes, order)
|
||||||
|
|
||||||
return
|
return
|
||||||
bit.bor(
|
bit.bor(
|
||||||
bit.bor(
|
bit.bor(
|
||||||
@ -226,20 +303,26 @@ function bit_converter.bytes_to_uint32(bytes)
|
|||||||
bit.lshift(bytes[3], 8)),bytes[4])
|
bit.lshift(bytes[3], 8)),bytes[4])
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.bytes_to_uint16(bytes)
|
function bit_converter.bytes_to_uint16(bytes, order)
|
||||||
if #bytes < 2 then
|
if #bytes < 2 then
|
||||||
error("eof")
|
error("eof")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
bytes = toLE(bytes, order)
|
||||||
|
|
||||||
return
|
return
|
||||||
bit.bor(
|
bit.bor(
|
||||||
bit.lshift(bytes[1], 8),
|
bit.lshift(bytes[1], 8),
|
||||||
bytes[2], 0)
|
bytes[2], 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.bytes_to_int64(bytes)
|
function bit_converter.bytes_to_int64(bytes, order)
|
||||||
if #bytes < 8 then
|
if #bytes < 8 then
|
||||||
error("eof")
|
error("eof")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
bytes = toLE(bytes, order)
|
||||||
|
|
||||||
return
|
return
|
||||||
bit.bor(
|
bit.bor(
|
||||||
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))
|
bit.lshift(bit.band(bytes[7], 0xFF), 8)),bit.band(bytes[8], 0xFF))
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.bytes_to_int32(bytes)
|
function bit_converter.bytes_to_int32(bytes, order)
|
||||||
return bit_converter.bytes_to_uint32(bytes) - MAX_INT32
|
on_deprecated_call("bit_converter.bytes_to_int32", "bit_converter.bytes_to_sint32")
|
||||||
|
return bit_converter.bytes_to_uint32(bytes, order) - MAX_INT32
|
||||||
end
|
end
|
||||||
|
|
||||||
function bit_converter.bytes_to_int16(bytes)
|
function bit_converter.bytes_to_int16(bytes, order)
|
||||||
return bit_converter.bytes_to_uint16(bytes) - MAX_INT16
|
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
|
end
|
||||||
|
|
||||||
return bit_converter
|
return bit_converter
|
||||||
|
|||||||
@ -18,22 +18,31 @@ local TYPE_UINT32 = 2
|
|||||||
local TYPE_INT16 = 3
|
local TYPE_INT16 = 3
|
||||||
local TYPE_INT32 = 4
|
local TYPE_INT32 = 4
|
||||||
local TYPE_INT64 = 5
|
local TYPE_INT64 = 5
|
||||||
local TYPE_DOUBLE = 6
|
local TYPE_FLOAT64 = 6
|
||||||
|
local TYPE_SINT16 = 7
|
||||||
|
local TYPE_SINT32 = 8
|
||||||
|
|
||||||
-- Data buffer
|
-- Data buffer
|
||||||
|
|
||||||
local data_buffer =
|
local data_buffer =
|
||||||
{
|
{
|
||||||
__call =
|
__call =
|
||||||
function(data_buffer, bytes)
|
function(data_buffer, ...)
|
||||||
return data_buffer:new(bytes)
|
return data_buffer:new(...)
|
||||||
end
|
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 = {
|
local obj = {
|
||||||
pos = 1,
|
pos = 1,
|
||||||
bytes = bytes or { }
|
order = order,
|
||||||
|
useBytearray = useBytearray or false,
|
||||||
|
bytes = useBytearray and Bytearray(bytes) or bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
self.__index = self
|
self.__index = self
|
||||||
@ -42,6 +51,13 @@ function data_buffer:new(bytes)
|
|||||||
return obj
|
return obj
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function data_buffer:set_order(order)
|
||||||
|
bit_converter.validate_order(order)
|
||||||
|
|
||||||
|
self.order = order
|
||||||
|
self.floatsOrder = order
|
||||||
|
end
|
||||||
|
|
||||||
-- Push functions
|
-- Push functions
|
||||||
|
|
||||||
function data_buffer:put_byte(byte)
|
function data_buffer:put_byte(byte)
|
||||||
@ -49,7 +65,8 @@ function data_buffer:put_byte(byte)
|
|||||||
error("invalid byte")
|
error("invalid byte")
|
||||||
end
|
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
|
self.pos = self.pos + 1
|
||||||
end
|
end
|
||||||
@ -61,11 +78,21 @@ function data_buffer:put_bytes(bytes)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function data_buffer:put_single(single)
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:put_double(double)
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:put_string(str)
|
function data_buffer:put_string(str)
|
||||||
@ -77,23 +104,33 @@ function data_buffer:put_bool(bool)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function data_buffer:put_uint16(uint16)
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:put_uint32(uint32)
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:put_int16(int16)
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:put_int32(int32)
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:put_int64(int64)
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:put_number(num)
|
function data_buffer:put_number(num)
|
||||||
@ -101,8 +138,8 @@ function data_buffer:put_number(num)
|
|||||||
local type
|
local type
|
||||||
|
|
||||||
if math.floor(num) ~= num then
|
if math.floor(num) ~= num then
|
||||||
type = TYPE_DOUBLE
|
type = TYPE_FLOAT64
|
||||||
bytes = bit_converter.double_to_bytes(num)
|
bytes = bit_converter.float64_to_bytes(num)
|
||||||
elseif num == 0 then
|
elseif num == 0 then
|
||||||
type = TYPE_ZERO
|
type = TYPE_ZERO
|
||||||
bytes = { }
|
bytes = { }
|
||||||
@ -119,11 +156,11 @@ function data_buffer:put_number(num)
|
|||||||
end
|
end
|
||||||
elseif num < 0 then
|
elseif num < 0 then
|
||||||
if num >= MIN_INT16 then
|
if num >= MIN_INT16 then
|
||||||
type = TYPE_INT16
|
type = TYPE_SINT16
|
||||||
bytes = bit_converter.int16_to_bytes(num)
|
bytes = bit_converter.sint16_to_bytes(num)
|
||||||
elseif num >= MIN_INT32 then
|
elseif num >= MIN_INT32 then
|
||||||
type = TYPE_INT32
|
type = TYPE_SINT32
|
||||||
bytes = bit_converter.int32_to_bytes(num)
|
bytes = bit_converter.sint32_to_bytes(num)
|
||||||
elseif num >= MIN_INT64 then
|
elseif num >= MIN_INT64 then
|
||||||
type = TYPE_INT64
|
type = TYPE_INT64
|
||||||
bytes = bit_converter.int64_to_bytes(num)
|
bytes = bit_converter.int64_to_bytes(num)
|
||||||
@ -155,9 +192,13 @@ function data_buffer:get_number()
|
|||||||
return self:get_int16()
|
return self:get_int16()
|
||||||
elseif type == TYPE_INT32 then
|
elseif type == TYPE_INT32 then
|
||||||
return self:get_int32()
|
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
|
elseif type == TYPE_INT64 then
|
||||||
return self:get_int64()
|
return self:get_int64()
|
||||||
elseif type == TYPE_DOUBLE then
|
elseif type == TYPE_FLOAT64 then
|
||||||
return self:get_double()
|
return self:get_double()
|
||||||
else
|
else
|
||||||
error("unknown lua number type: "..type)
|
error("unknown lua number type: "..type)
|
||||||
@ -165,11 +206,21 @@ function data_buffer:get_number()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function data_buffer:get_single()
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:get_double()
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:get_string()
|
function data_buffer:get_string()
|
||||||
@ -193,23 +244,33 @@ function data_buffer:get_bool()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function data_buffer:get_uint16()
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:get_uint32()
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:get_int16()
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:get_int32()
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:get_int64()
|
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
|
end
|
||||||
|
|
||||||
function data_buffer:size()
|
function data_buffer:size()
|
||||||
|
|||||||
@ -42,6 +42,7 @@ local Socket = {__index={
|
|||||||
close=function(self) return network.__close(self.id) end,
|
close=function(self) return network.__close(self.id) end,
|
||||||
is_alive=function(self) return network.__is_alive(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,
|
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)
|
network.tcp_connect = function(address, port, callback)
|
||||||
@ -55,6 +56,7 @@ end
|
|||||||
local ServerSocket = {__index={
|
local ServerSocket = {__index={
|
||||||
close=function(self) return network.__closeserver(self.id) end,
|
close=function(self) return network.__closeserver(self.id) end,
|
||||||
is_open=function(self) return network.__is_serveropen(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)
|
network.tcp_open = function(port, handler)
|
||||||
|
|||||||
@ -63,6 +63,20 @@ function table.copy(t)
|
|||||||
return copied
|
return copied
|
||||||
end
|
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)
|
function table.count_pairs(t)
|
||||||
local count = 0
|
local count = 0
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Общее
|
# Umumiy
|
||||||
Yes=Ha
|
Yes=Ha
|
||||||
No=Yo'q
|
No=Yo'q
|
||||||
Ok=Ок
|
Ok=Ок
|
||||||
@ -10,18 +10,26 @@ Version=Versiya
|
|||||||
Creator=Muallif
|
Creator=Muallif
|
||||||
Dependencies=Bog'liqliklar
|
Dependencies=Bog'liqliklar
|
||||||
Description=Tavsif
|
Description=Tavsif
|
||||||
Converting world...=Dunyoni konvertatsiyalash amalga oshirilyapti...
|
Converting world...=Dunyo konvertatsiya qilinmoqda...
|
||||||
Unlimited=Cheksiz
|
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.pack-not-found=Paketni topib bo'lmadi
|
||||||
error.dependency-not-found=Amaldagi qaramliklar topilmadi
|
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.gamma.tooltip=Yorug'lik yorqinligi egri chizig'i
|
||||||
graphics.backlight.tooltip=To'liq zulmatni oldini oladigan orqa yorug'ligi
|
graphics.backlight.tooltip=To'liq zulmatni oldini oladigan orqa yorug'ligi
|
||||||
|
|
||||||
# Меню
|
# Menyu
|
||||||
menu.Apply=Qo'llash
|
menu.Apply=Qo'llash
|
||||||
menu.Audio=Tovush
|
menu.Audio=Tovush
|
||||||
menu.Back to Main Menu=Menyuga qaytish
|
menu.Back to Main Menu=Menyuga qaytish
|
||||||
@ -31,60 +39,72 @@ menu.Continue=Davom ettirish
|
|||||||
menu.Controls=Boshqaruv
|
menu.Controls=Boshqaruv
|
||||||
menu.Display=Displey
|
menu.Display=Displey
|
||||||
menu.Graphics=Grafika
|
menu.Graphics=Grafika
|
||||||
menu.missing-content=Kontent etishmayapti!
|
menu.missing-content=Kontent mavjud emas!
|
||||||
menu.New World=Yangi Dunyo
|
menu.New World=Yangi Dunyo
|
||||||
menu.Worlds=Dunyo
|
menu.Open worlds folder=Dunyolar papkasini ochish
|
||||||
menu.Open worlds folder=Dunyo papkasini ochish
|
menu.Worlds=Dunyolar
|
||||||
menu.Page not found=Sahifa topilmadi
|
menu.Page not found=Sahifa topilmadi
|
||||||
menu.Quit=Chiqish
|
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.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.Seed=Don
|
||||||
world.Name=Nom
|
world.Name=Nom
|
||||||
world.World generator=Dunyo yaratuvchi
|
world.World generator=Dunyo generatori
|
||||||
world.generators.default=Oddiy
|
world.generators.default=Standart bo'yicha
|
||||||
world.generators.flat=Yassi
|
world.generators.flat=Tekis
|
||||||
world.Create World=Dunyoni Yaratish
|
world.Create World=Dunyo yaratish
|
||||||
world.convert-request=Indekslarda o‘zgarishlar mavjud! Dunyoni konvertatsiya qilish kerakmi?
|
world.convert-request=Indekslar bo'yicha o'zgarishlar bor! Dunyoni konvertatsiya qilasizmi?
|
||||||
world.delete-confirm=Dunyoni qaytarib bo'lmaydigan tarzda olib tashlaysizmi?
|
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.Ambient=Fon
|
||||||
settings.Backlight=Yoritish
|
settings.Backlight=Yoritish
|
||||||
settings.Camera Shaking=Kamera Silkinishi
|
settings.Camera Shaking=Kamera titrashi
|
||||||
settings.Camera Inertia=Kamera Inertsiyasi
|
settings.Camera Inertia=Kamera inertsiyasi
|
||||||
settings.Fog Curve=Tuman Egri Chizig'i
|
settings.Camera FOV Effects=Ko'rish maydoni effektlari
|
||||||
settings.FOV=Ko'rish Maydoni
|
settings.Fog Curve=Tuman egri chizig'i
|
||||||
|
settings.FOV=Ko'rish maydoni
|
||||||
settings.Fullscreen=To'liq ekran
|
settings.Fullscreen=To'liq ekran
|
||||||
settings.Framerate=Kadr tezligi
|
settings.Framerate=Kadrlar chastotasi
|
||||||
settings.Gamma=Gamma
|
settings.Gamma=Gamma
|
||||||
settings.Language=Til
|
settings.Language=Til
|
||||||
settings.Load Distance=Yuklash Masofasi
|
settings.Load Distance=Yuklash masofasi
|
||||||
settings.Load Speed=Yuklash Tezligi
|
settings.Load Speed=Yuklash tezligi
|
||||||
settings.Master Volume=Umumiy Ovoz Balandligi
|
settings.Master Volume=Umumiy ovoz balansi
|
||||||
settings.Mouse Sensitivity=Sichqoncha Sezgirligi
|
settings.Mouse Sensitivity=Sichqoncha sezgirligi
|
||||||
settings.Music=Musiqa
|
settings.Music=Musiqa
|
||||||
settings.Regular Sounds=Oddiy Tovushlar
|
settings.Regular Sounds=Oddiy tovushlar
|
||||||
settings.UI Sounds=Interfeys Tovushlari
|
settings.UI Sounds=Interfeys tovushlari
|
||||||
settings.V-Sync=Vertikal Sinxronizatsiya
|
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
|
chunks.reload=Chanklarni qayta yuklash
|
||||||
devtools.console=Konsol
|
devtools.console=Konsol
|
||||||
movement.forward=Oldinga
|
movement.forward=Oldinga
|
||||||
movement.back=Orqaga
|
movement.back=Orqaga
|
||||||
movement.left=Chapga
|
movement.left=Chapga
|
||||||
movement.right=O'ng tomonda
|
movement.right=O'ngga
|
||||||
movement.jump=Sakrash
|
movement.jump=Sakrash
|
||||||
movement.sprint=Tezlanish
|
movement.sprint=Tez yugurish
|
||||||
movement.crouch=Egilish
|
movement.crouch=Egilish
|
||||||
movement.cheat=Chit
|
movement.cheat=Hiyla (Chit)
|
||||||
hud.inventory=inventar
|
hud.inventory=Inventar
|
||||||
player.pick=Blokni olish
|
player.pick=Blokni olish
|
||||||
player.attack=Hujum Qilish / Sindirish
|
player.attack=Hujum qilish
|
||||||
player.build=Blokni Joylashtiring
|
player.destroy=Sindirish
|
||||||
|
player.build=Blokni qo'yish
|
||||||
|
player.fast_interaction=Tezkor o'zaro ta'sir
|
||||||
player.flight=Parvoz
|
player.flight=Parvoz
|
||||||
player.drop=Narsani tashlash
|
player.drop=Narsani tashlash
|
||||||
camera.zoom=Yaqinlashish
|
camera.zoom=Yaqinlashish
|
||||||
|
|||||||
@ -214,6 +214,28 @@ std::string_view BasicParser::readUntil(char c) {
|
|||||||
return source.substr(start, pos - start);
|
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() {
|
std::string_view BasicParser::readUntilEOL() {
|
||||||
int start = pos;
|
int start = pos;
|
||||||
while (hasNext() && source[pos] != '\r' && source[pos] != '\n') {
|
while (hasNext() && source[pos] != '\r' && source[pos] != '\n') {
|
||||||
|
|||||||
@ -105,6 +105,8 @@ protected:
|
|||||||
parsing_error error(const std::string& message);
|
parsing_error error(const std::string& message);
|
||||||
public:
|
public:
|
||||||
std::string_view readUntil(char c);
|
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_view readUntilEOL();
|
||||||
std::string parseName();
|
std::string parseName();
|
||||||
std::string parseXmlName();
|
std::string parseXmlName();
|
||||||
|
|||||||
@ -11,15 +11,17 @@
|
|||||||
|
|
||||||
using namespace json;
|
using namespace json;
|
||||||
|
|
||||||
class Parser : BasicParser {
|
namespace {
|
||||||
|
class Parser : BasicParser {
|
||||||
dv::value parseList();
|
dv::value parseList();
|
||||||
dv::value parseObject();
|
dv::value parseObject();
|
||||||
dv::value parseValue();
|
dv::value parseValue();
|
||||||
public:
|
public:
|
||||||
Parser(std::string_view filename, std::string_view source);
|
Parser(std::string_view filename, std::string_view source);
|
||||||
|
|
||||||
dv::value parse();
|
dv::value parse();
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
inline void newline(
|
inline void newline(
|
||||||
std::stringstream& ss, bool nice, uint indent, const std::string& indentstr
|
std::stringstream& ss, bool nice, uint indent, const std::string& indentstr
|
||||||
|
|||||||
188
src/coders/lua_parsing.cpp
Normal file
188
src/coders/lua_parsing.cpp
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
#include "lua_parsing.hpp"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "commons.hpp"
|
||||||
|
|
||||||
|
using namespace lua;
|
||||||
|
using namespace devtools;
|
||||||
|
|
||||||
|
static std::set<std::string_view> 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<Token> 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<int>(pos),
|
||||||
|
static_cast<int>(linestart),
|
||||||
|
static_cast<int>(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<Token> 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<Token> lua::tokenize(std::string_view file, std::string_view source) {
|
||||||
|
return Tokenizer(file, source).tokenize();
|
||||||
|
}
|
||||||
14
src/coders/lua_parsing.hpp
Normal file
14
src/coders/lua_parsing.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "devtools/syntax.hpp"
|
||||||
|
|
||||||
|
namespace lua {
|
||||||
|
bool is_lua_keyword(std::string_view view);
|
||||||
|
|
||||||
|
std::vector<devtools::Token> tokenize(
|
||||||
|
std::string_view file, std::string_view source
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@
|
|||||||
static debug::Logger logger("png-coder");
|
static debug::Logger logger("png-coder");
|
||||||
|
|
||||||
// returns 0 if all-right, 1 otherwise
|
// 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
|
const char* filename, uint width, uint height, const ubyte* data, bool alpha
|
||||||
) {
|
) {
|
||||||
uint pixsize = alpha ? 4 : 3;
|
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<ImageData> png::load_image(const ubyte* bytes, size_t size) {
|
std::unique_ptr<ImageData> 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");
|
throw std::runtime_error("invalid png signature");
|
||||||
}
|
}
|
||||||
png_structp pngPtr = nullptr;
|
png_structp pngPtr = nullptr;
|
||||||
@ -223,7 +223,7 @@ std::unique_ptr<Texture> png::load_texture(const std::string& filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void png::write_image(const std::string& filename, const ImageData* image) {
|
void png::write_image(const std::string& filename, const ImageData* image) {
|
||||||
_png_write(
|
png_write(
|
||||||
filename.c_str(),
|
filename.c_str(),
|
||||||
image->getWidth(),
|
image->getWidth(),
|
||||||
image->getHeight(),
|
image->getHeight(),
|
||||||
|
|||||||
@ -107,8 +107,8 @@ glm::vec4 Attribute::asColor() const {
|
|||||||
Node::Node(std::string tag) : tag(std::move(tag)) {
|
Node::Node(std::string tag) : tag(std::move(tag)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::add(const xmlelement& element) {
|
void Node::add(std::unique_ptr<Node> element) {
|
||||||
elements.push_back(element);
|
elements.push_back(std::move(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::set(const std::string& name, const std::string& text) {
|
void Node::set(const std::string& name, const std::string& text) {
|
||||||
@ -119,7 +119,7 @@ const std::string& Node::getTag() const {
|
|||||||
return tag;
|
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);
|
auto found = attrs.find(name);
|
||||||
if (found == attrs.end()) {
|
if (found == attrs.end()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
@ -129,7 +129,7 @@ const xmlattribute& Node::attr(const std::string& name) const {
|
|||||||
return found->second;
|
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);
|
auto found = attrs.find(name);
|
||||||
if (found == attrs.end()) {
|
if (found == attrs.end()) {
|
||||||
return Attribute(name, def);
|
return Attribute(name, def);
|
||||||
@ -142,19 +142,23 @@ bool Node::has(const std::string& name) const {
|
|||||||
return found != attrs.end();
|
return found != attrs.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlelement Node::sub(size_t index) {
|
Node& Node::sub(size_t index) {
|
||||||
return elements.at(index);
|
return *elements.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Node& Node::sub(size_t index) const {
|
||||||
|
return *elements.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Node::size() const {
|
size_t Node::size() const {
|
||||||
return elements.size();
|
return elements.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<xmlelement>& Node::getElements() const {
|
const std::vector<std::unique_ptr<Node>>& Node::getElements() const {
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
const xmlelements_map& Node::getAttributes() const {
|
const std::unordered_map<std::string, Attribute>& Node::getAttributes() const {
|
||||||
return attrs;
|
return attrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,12 +166,12 @@ Document::Document(std::string version, std::string encoding)
|
|||||||
: version(std::move(version)), encoding(std::move(encoding)) {
|
: version(std::move(version)), encoding(std::move(encoding)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::setRoot(const xmlelement& element) {
|
void Document::setRoot(std::unique_ptr<Node> element) {
|
||||||
this->root = element;
|
root = std::move(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlelement Document::getRoot() const {
|
const Node* Document::getRoot() const {
|
||||||
return root;
|
return root.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Document::getVersion() const {
|
const std::string& Document::getVersion() const {
|
||||||
@ -178,13 +182,21 @@ const std::string& Document::getEncoding() const {
|
|||||||
return encoding;
|
return encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::Parser(std::string_view filename, std::string_view source)
|
inline bool is_xml_identifier_start(char c) {
|
||||||
: BasicParser(filename, source) {
|
return is_identifier_start(c) || c == ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlelement Parser::parseOpenTag() {
|
inline bool is_xml_identifier_part(char c) {
|
||||||
|
return is_identifier_part(c) || c == '-' || c == '.' || c == ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class Parser : BasicParser {
|
||||||
|
std::unique_ptr<Document> document;
|
||||||
|
|
||||||
|
std::unique_ptr<Node> parseOpenTag() {
|
||||||
std::string tag = parseXMLName();
|
std::string tag = parseXMLName();
|
||||||
auto node = std::make_shared<Node>(tag);
|
auto node = std::make_unique<Node>(tag);
|
||||||
|
|
||||||
char c;
|
char c;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -208,76 +220,12 @@ xmlelement Parser::parseOpenTag() {
|
|||||||
node->set(attrname, attrtext);
|
node->set(attrname, attrtext);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::parseDeclaration() {
|
std::unique_ptr<Node> parseElement() {
|
||||||
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<Document>(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 == ':';
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlelement Parser::parseElement() {
|
|
||||||
// text element
|
// text element
|
||||||
if (peek() != '<') {
|
if (peek() != '<') {
|
||||||
auto element = std::make_shared<Node>("#");
|
auto element = std::make_unique<Node>("#");
|
||||||
auto text = parseText();
|
auto text = parseText();
|
||||||
util::replaceAll(text, """, "\"");
|
util::replaceAll(text, """, "\"");
|
||||||
util::replaceAll(text, "'", "'");
|
util::replaceAll(text, "'", "'");
|
||||||
@ -311,7 +259,7 @@ xmlelement Parser::parseElement() {
|
|||||||
while (!isNext("</")) {
|
while (!isNext("</")) {
|
||||||
auto sub = parseElement();
|
auto sub = parseElement();
|
||||||
if (sub) {
|
if (sub) {
|
||||||
element->add(sub);
|
element->add(std::move(sub));
|
||||||
}
|
}
|
||||||
skipWhitespace();
|
skipWhitespace();
|
||||||
}
|
}
|
||||||
@ -324,20 +272,84 @@ xmlelement Parser::parseElement() {
|
|||||||
throw error("invalid syntax");
|
throw error("invalid syntax");
|
||||||
}
|
}
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmldocument Parser::parse() {
|
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");
|
||||||
|
}
|
||||||
|
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_unique<Document>(version, encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseComment() {
|
||||||
|
expect("!--");
|
||||||
|
if (skipTo("-->")) {
|
||||||
|
skip(3);
|
||||||
|
} else {
|
||||||
|
throw error("comment close missing");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Document> parse() {
|
||||||
parseDeclaration();
|
parseDeclaration();
|
||||||
|
|
||||||
xmlelement root = nullptr;
|
std::unique_ptr<Node> root;
|
||||||
while (root == nullptr) {
|
while (root == nullptr) {
|
||||||
root = parseElement();
|
root = parseElement();
|
||||||
}
|
}
|
||||||
document->setRoot(root);
|
document->setRoot(std::move(root));
|
||||||
return document;
|
return std::move(document);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
xmldocument xml::parse(std::string_view filename, std::string_view source) {
|
std::unique_ptr<Document> xml::parse(
|
||||||
|
std::string_view filename, std::string_view source
|
||||||
|
) {
|
||||||
Parser parser(filename, source);
|
Parser parser(filename, source);
|
||||||
return parser.parse();
|
return parser.parse();
|
||||||
}
|
}
|
||||||
@ -354,13 +366,13 @@ inline void newline(
|
|||||||
|
|
||||||
static void stringifyElement(
|
static void stringifyElement(
|
||||||
std::stringstream& ss,
|
std::stringstream& ss,
|
||||||
const xmlelement& element,
|
const Node& element,
|
||||||
bool nice,
|
bool nice,
|
||||||
const std::string& indentStr,
|
const std::string& indentStr,
|
||||||
int indent
|
int indent
|
||||||
) {
|
) {
|
||||||
if (element->isText()) {
|
if (element.isText()) {
|
||||||
std::string text = element->attr("#").getText();
|
std::string text = element.attr("#").getText();
|
||||||
util::replaceAll(text, "&", "&");
|
util::replaceAll(text, "&", "&");
|
||||||
util::replaceAll(text, "\"", """);
|
util::replaceAll(text, "\"", """);
|
||||||
util::replaceAll(text, "'", "'");
|
util::replaceAll(text, "'", "'");
|
||||||
@ -369,10 +381,10 @@ static void stringifyElement(
|
|||||||
ss << text;
|
ss << text;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const std::string& tag = element->getTag();
|
const std::string& tag = element.getTag();
|
||||||
|
|
||||||
ss << '<' << tag;
|
ss << '<' << tag;
|
||||||
auto& attrs = element->getAttributes();
|
auto& attrs = element.getAttributes();
|
||||||
if (!attrs.empty()) {
|
if (!attrs.empty()) {
|
||||||
ss << ' ';
|
ss << ' ';
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@ -388,10 +400,10 @@ static void stringifyElement(
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto& elements = element->getElements();
|
auto& elements = element.getElements();
|
||||||
if (elements.size() == 1 && elements[0]->isText()) {
|
if (elements.size() == 1 && elements[0]->isText()) {
|
||||||
ss << ">";
|
ss << ">";
|
||||||
stringifyElement(ss, elements[0], nice, indentStr, indent + 1);
|
stringifyElement(ss, *elements[0], nice, indentStr, indent + 1);
|
||||||
ss << "</" << tag << ">";
|
ss << "</" << tag << ">";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -399,7 +411,7 @@ static void stringifyElement(
|
|||||||
ss << '>';
|
ss << '>';
|
||||||
for (auto& sub : elements) {
|
for (auto& sub : elements) {
|
||||||
newline(ss, nice, indentStr, indent + 1);
|
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);
|
newline(ss, nice, indentStr, indent);
|
||||||
ss << "</" << tag << ">";
|
ss << "</" << tag << ">";
|
||||||
@ -410,16 +422,16 @@ static void stringifyElement(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string xml::stringify(
|
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;
|
std::stringstream ss;
|
||||||
|
|
||||||
// XML declaration
|
// XML declaration
|
||||||
ss << "<?xml version=\"" << document->getVersion();
|
ss << "<?xml version=\"" << document.getVersion();
|
||||||
ss << "\" encoding=\"UTF-8\" ?>";
|
ss << "\" encoding=\"UTF-8\" ?>";
|
||||||
newline(ss, nice, indentStr, 0);
|
newline(ss, nice, indentStr, 0);
|
||||||
|
|
||||||
stringifyElement(ss, document->getRoot(), nice, indentStr, 0);
|
stringifyElement(ss, *document.getRoot(), nice, indentStr, 0);
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,11 +13,6 @@ namespace xml {
|
|||||||
class Attribute;
|
class Attribute;
|
||||||
class Document;
|
class Document;
|
||||||
|
|
||||||
using xmlattribute = Attribute;
|
|
||||||
using xmlelement = std::shared_ptr<Node>;
|
|
||||||
using xmldocument = std::shared_ptr<Document>;
|
|
||||||
using xmlelements_map = std::unordered_map<std::string, xmlattribute>;
|
|
||||||
|
|
||||||
class Attribute {
|
class Attribute {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string text;
|
std::string text;
|
||||||
@ -40,13 +35,15 @@ namespace xml {
|
|||||||
/// 'text'
|
/// 'text'
|
||||||
class Node {
|
class Node {
|
||||||
std::string tag;
|
std::string tag;
|
||||||
std::unordered_map<std::string, xmlattribute> attrs;
|
std::unordered_map<std::string, Attribute> attrs;
|
||||||
std::vector<xmlelement> elements;
|
std::vector<std::unique_ptr<Node>> elements;
|
||||||
public:
|
public:
|
||||||
Node(std::string tag);
|
Node(std::string tag);
|
||||||
|
|
||||||
|
Node(const Node&) = delete;
|
||||||
|
|
||||||
/// @brief Add sub-element
|
/// @brief Add sub-element
|
||||||
void add(const xmlelement& element);
|
void add(std::unique_ptr<Node> element);
|
||||||
|
|
||||||
/// @brief Set attribute value. Creates attribute if does not exists
|
/// @brief Set attribute value. Creates attribute if does not exists
|
||||||
/// @param name attribute name
|
/// @param name attribute name
|
||||||
@ -67,15 +64,15 @@ namespace xml {
|
|||||||
/// @brief Get attribute by name
|
/// @brief Get attribute by name
|
||||||
/// @param name attribute name
|
/// @param name attribute name
|
||||||
/// @throws std::runtime_error if element has no attribute
|
/// @throws std::runtime_error if element has no attribute
|
||||||
/// @return xmlattribute - {name, value}
|
/// @return xml attribute - {name, value}
|
||||||
const xmlattribute& attr(const std::string& name) const;
|
const Attribute& attr(const std::string& name) const;
|
||||||
|
|
||||||
/// @brief Get attribute by name
|
/// @brief Get attribute by name
|
||||||
/// @param name attribute name
|
/// @param name attribute name
|
||||||
/// @param def default value will be returned wrapped in xmlattribute
|
/// @param def default value will be returned wrapped in xmlattribute
|
||||||
/// if element has no attribute
|
/// if element has no attribute
|
||||||
/// @return xmlattribute - {name, value} or {name, def} if not found*/
|
/// @return xml attribute - {name, value} or {name, def} if not found
|
||||||
xmlattribute attr(const std::string& name, const std::string& def)
|
Attribute attr(const std::string& name, const std::string& def)
|
||||||
const;
|
const;
|
||||||
|
|
||||||
/// @brief Check if element has attribute
|
/// @brief Check if element has attribute
|
||||||
@ -86,51 +83,37 @@ namespace xml {
|
|||||||
/// @param index sub-element index
|
/// @param index sub-element index
|
||||||
/// @throws std::out_of_range if an invalid index given
|
/// @throws std::out_of_range if an invalid index given
|
||||||
/// @return sub-element
|
/// @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
|
/// @brief Get number of sub-elements
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
|
|
||||||
const std::vector<xmlelement>& getElements() const;
|
const std::vector<std::unique_ptr<Node>>& getElements() const;
|
||||||
const xmlelements_map& getAttributes() const;
|
const std::unordered_map<std::string, Attribute>& getAttributes() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Document {
|
class Document {
|
||||||
xmlelement root = nullptr;
|
std::unique_ptr<Node> root = nullptr;
|
||||||
std::string version;
|
std::string version;
|
||||||
std::string encoding;
|
std::string encoding;
|
||||||
public:
|
public:
|
||||||
Document(std::string version, std::string encoding);
|
Document(std::string version, std::string encoding);
|
||||||
|
|
||||||
void setRoot(const xmlelement& element);
|
void setRoot(std::unique_ptr<Node> element);
|
||||||
xmlelement getRoot() const;
|
const Node* getRoot() const;
|
||||||
|
|
||||||
const std::string& getVersion() const;
|
const std::string& getVersion() const;
|
||||||
const std::string& getEncoding() 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
|
/// @brief Serialize XML Document to string
|
||||||
/// @param document serializing document
|
/// @param document serializing document
|
||||||
/// @param nice use human readable format (with indents and line-separators)
|
/// @param nice use human readable format (with indents and line-separators)
|
||||||
/// @param indentStr indentation characters sequence (default - 4 spaces)
|
/// @param indentStr indentation characters sequence (default - 4 spaces)
|
||||||
/// @return XML string
|
/// @return XML string
|
||||||
extern std::string stringify(
|
std::string stringify(
|
||||||
const xmldocument& document,
|
const Document& document,
|
||||||
bool nice = true,
|
bool nice = true,
|
||||||
const std::string& indentStr = " "
|
const std::string& indentStr = " "
|
||||||
);
|
);
|
||||||
@ -139,7 +122,9 @@ namespace xml {
|
|||||||
/// @param filename file name will be shown in error messages
|
/// @param filename file name will be shown in error messages
|
||||||
/// @param source xml source code string
|
/// @param source xml source code string
|
||||||
/// @return xml document
|
/// @return xml document
|
||||||
extern xmldocument parse(
|
std::unique_ptr<Document> parse(
|
||||||
std::string_view filename, std::string_view source
|
std::string_view filename, std::string_view source
|
||||||
);
|
);
|
||||||
|
|
||||||
|
using xmlelement = Node;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
inline constexpr int ENGINE_VERSION_MAJOR = 0;
|
inline constexpr int ENGINE_VERSION_MAJOR = 0;
|
||||||
inline constexpr int ENGINE_VERSION_MINOR = 25;
|
inline constexpr int ENGINE_VERSION_MINOR = 26;
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
inline constexpr bool ENGINE_DEBUG_BUILD = false;
|
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;
|
inline constexpr bool ENGINE_DEBUG_BUILD = true;
|
||||||
#endif // NDEBUG
|
#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
|
/// @brief world regions format version
|
||||||
inline constexpr uint REGION_FORMAT_VERSION = 3;
|
inline constexpr uint REGION_FORMAT_VERSION = 3;
|
||||||
|
|||||||
30
src/devtools/syntax.hpp
Normal file
30
src/devtools/syntax.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
72
src/devtools/syntax_highlighting.cpp
Normal file
72
src/devtools/syntax_highlighting.cpp
Normal file
@ -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<FontStylesScheme> build_styles(
|
||||||
|
const std::vector<devtools::Token>& 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<FontStylesScheme>(std::move(styles));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<FontStylesScheme> devtools::syntax_highlight(
|
||||||
|
const std::string& lang, std::string_view source
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
if (lang == "lua") {
|
||||||
|
auto tokens = lua::tokenize("<string>", source);
|
||||||
|
return build_styles(tokens);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} catch (const parsing_error& err) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/devtools/syntax_highlighting.hpp
Normal file
16
src/devtools/syntax_highlighting.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
struct FontStylesScheme;
|
||||||
|
|
||||||
|
namespace devtools {
|
||||||
|
enum SyntaxStyles {
|
||||||
|
DEFAULT, KEYWORD, LITERAL, COMMENT, ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<FontStylesScheme> syntax_highlight(
|
||||||
|
const std::string& lang, std::string_view source
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -206,7 +206,7 @@ void Engine::renderFrame(Batch2D& batch) {
|
|||||||
|
|
||||||
Viewport viewport(Window::width, Window::height);
|
Viewport viewport(Window::width, Window::height);
|
||||||
DrawContext ctx(nullptr, viewport, &batch);
|
DrawContext ctx(nullptr, viewport, &batch);
|
||||||
gui->draw(&ctx, assets.get());
|
gui->draw(ctx, *assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::processPostRunnables() {
|
void Engine::processPostRunnables() {
|
||||||
|
|||||||
@ -67,9 +67,7 @@ std::unique_ptr<UiDocument> UiDocument::read(
|
|||||||
: scripting::create_doc_environment(penv, name);
|
: scripting::create_doc_environment(penv, name);
|
||||||
|
|
||||||
gui::UiXmlReader reader(env);
|
gui::UiXmlReader reader(env);
|
||||||
auto view = reader.readXML(
|
auto view = reader.readXML(file.u8string(), *xmldoc->getRoot());
|
||||||
file.u8string(), xmldoc->getRoot()
|
|
||||||
);
|
|
||||||
view->setId("root");
|
view->setId("root");
|
||||||
uidocscript script {};
|
uidocscript script {};
|
||||||
auto scriptFile = fs::path(file.u8string()+".lua");
|
auto scriptFile = fs::path(file.u8string()+".lua");
|
||||||
|
|||||||
@ -124,7 +124,7 @@ std::shared_ptr<InventoryView> Hud::createContentAccess() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
InventoryBuilder builder;
|
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();
|
auto view = builder.build();
|
||||||
view->bind(accessInventory, content);
|
view->bind(accessInventory, content);
|
||||||
view->setMargin(glm::vec4());
|
view->setMargin(glm::vec4());
|
||||||
@ -137,7 +137,7 @@ std::shared_ptr<InventoryView> Hud::createHotbar() {
|
|||||||
|
|
||||||
SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr);
|
SlotLayout slotLayout(-1, glm::vec2(), false, false, nullptr, nullptr, nullptr);
|
||||||
InventoryBuilder builder;
|
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();
|
auto view = builder.build();
|
||||||
view->setId("hud.hotbar");
|
view->setId("hud.hotbar");
|
||||||
view->setOrigin(glm::vec2(view->getSize().x/2, 0));
|
view->setOrigin(glm::vec2(view->getSize().x/2, 0));
|
||||||
@ -346,9 +346,9 @@ void Hud::update(bool visible) {
|
|||||||
element.getNode()->setVisible(visible);
|
element.getNode()->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 invSize = contentAccessPanel->getSize();
|
glm::vec2 caSize = contentAccessPanel->getSize();
|
||||||
contentAccessPanel->setVisible(inventoryView != nullptr && showContentPanel);
|
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));
|
contentAccess->setMinSize(glm::vec2(1, Window::height));
|
||||||
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
|
hotbarView->setVisible(visible && !(secondUI && !inventoryView));
|
||||||
|
|
||||||
|
|||||||
@ -95,16 +95,16 @@ class Hud : public util::ObjectsKeeper {
|
|||||||
/// @brief Inventories interaction agent (grabbed item)
|
/// @brief Inventories interaction agent (grabbed item)
|
||||||
std::shared_ptr<gui::SlotView> exchangeSlot;
|
std::shared_ptr<gui::SlotView> exchangeSlot;
|
||||||
/// @brief Exchange slot inventory (1 slot only)
|
/// @brief Exchange slot inventory (1 slot only)
|
||||||
std::shared_ptr<Inventory> exchangeSlotInv = nullptr;
|
std::shared_ptr<Inventory> exchangeSlotInv;
|
||||||
/// @brief List of all controlled hud elements
|
/// @brief List of all controlled hud elements
|
||||||
std::vector<HudElement> elements;
|
std::vector<HudElement> elements;
|
||||||
|
|
||||||
/// @brief Player inventory view
|
/// @brief Player inventory view
|
||||||
std::shared_ptr<gui::InventoryView> inventoryView = nullptr;
|
std::shared_ptr<gui::InventoryView> inventoryView;
|
||||||
/// @brief Block inventory view
|
/// @brief Block inventory view
|
||||||
std::shared_ptr<gui::InventoryView> blockUI = nullptr;
|
std::shared_ptr<gui::InventoryView> blockUI;
|
||||||
/// @brief Secondary inventory view
|
/// @brief Secondary inventory view
|
||||||
std::shared_ptr<gui::InventoryView> secondInvView = nullptr;
|
std::shared_ptr<gui::InventoryView> secondInvView;
|
||||||
/// @brief Position of the block open
|
/// @brief Position of the block open
|
||||||
glm::ivec3 blockPos {};
|
glm::ivec3 blockPos {};
|
||||||
/// @brief Id of the block open (used to detect block destruction or replacement)
|
/// @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
|
/// @brief Provide cheat controllers to the debug panel
|
||||||
bool allowDebugCheats = true;
|
bool allowDebugCheats = true;
|
||||||
/// @brief UI element will be dynamicly positioned near to inventory or in screen center
|
/// @brief UI element will be dynamicly positioned near to inventory or in screen center
|
||||||
std::shared_ptr<gui::UINode> secondUI = nullptr;
|
std::shared_ptr<gui::UINode> secondUI;
|
||||||
|
|
||||||
std::shared_ptr<gui::UINode> debugMinimap = nullptr;
|
std::shared_ptr<gui::UINode> debugMinimap;
|
||||||
|
|
||||||
std::unique_ptr<ImageData> debugImgWorldGen;
|
std::unique_ptr<ImageData> debugImgWorldGen;
|
||||||
|
|
||||||
|
|||||||
@ -261,6 +261,24 @@ void Batch2D::rect(
|
|||||||
vertex(x+w, y+h, u+tx, v, r,g,b,a);
|
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(
|
void Batch2D::rect(
|
||||||
float x, float y, float w, float h,
|
float x, float y, float w, float h,
|
||||||
float r0, float g0, float b0,
|
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);
|
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() {
|
void Batch2D::flush() {
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -45,6 +45,7 @@ public:
|
|||||||
void setRegion(UVRegion region);
|
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, 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, 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);
|
void point(float x, float y, float r, float g, float b, float a);
|
||||||
|
|
||||||
inline void setColor(glm::vec4 color) {
|
inline void setColor(glm::vec4 color) {
|
||||||
@ -79,6 +80,12 @@ public:
|
|||||||
float r, float g, float b, float a
|
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(
|
void rect(
|
||||||
float x, float y, float w, float h,
|
float x, float y, float w, float h,
|
||||||
float r0, float g0, float b0,
|
float r0, float g0, float b0,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "Font.hpp"
|
#include "Font.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "Texture.hpp"
|
#include "Texture.hpp"
|
||||||
#include "Batch2D.hpp"
|
#include "Batch2D.hpp"
|
||||||
@ -52,17 +53,21 @@ static inline void draw_glyph(
|
|||||||
uint c,
|
uint c,
|
||||||
const glm::vec3& right,
|
const glm::vec3& right,
|
||||||
const glm::vec3& up,
|
const glm::vec3& up,
|
||||||
float glyphInterval
|
float glyphInterval,
|
||||||
|
const FontStyle& style
|
||||||
) {
|
) {
|
||||||
|
for (int i = 0; i <= style.bold; i++) {
|
||||||
batch.sprite(
|
batch.sprite(
|
||||||
pos.x + offset.x * right.x,
|
pos.x + (offset.x + i / (right.x/glyphInterval/2.0f)) * right.x,
|
||||||
pos.y + offset.y * right.y,
|
pos.y + offset.y * right.y,
|
||||||
right.x / glyphInterval,
|
right.x / glyphInterval,
|
||||||
up.y,
|
up.y,
|
||||||
|
-0.15f * style.italic,
|
||||||
16,
|
16,
|
||||||
c,
|
c,
|
||||||
batch.getColor()
|
batch.getColor() * style.color
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void draw_glyph(
|
static inline void draw_glyph(
|
||||||
@ -72,17 +77,20 @@ static inline void draw_glyph(
|
|||||||
uint c,
|
uint c,
|
||||||
const glm::vec3& right,
|
const glm::vec3& right,
|
||||||
const glm::vec3& up,
|
const glm::vec3& up,
|
||||||
float glyphInterval
|
float glyphInterval,
|
||||||
|
const FontStyle& style
|
||||||
) {
|
) {
|
||||||
|
for (int i = 0; i <= style.bold; i++) {
|
||||||
batch.sprite(
|
batch.sprite(
|
||||||
pos + right * offset.x + up * offset.y,
|
pos + right * (offset.x + i) + up * offset.y,
|
||||||
up, right / glyphInterval,
|
up, right / glyphInterval,
|
||||||
0.5f,
|
0.5f,
|
||||||
0.5f,
|
0.5f,
|
||||||
16,
|
16,
|
||||||
c,
|
c,
|
||||||
batch.getColor()
|
batch.getColor() * style.color
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Batch>
|
template <class Batch>
|
||||||
@ -93,14 +101,32 @@ static inline void draw_text(
|
|||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::vec3& right,
|
const glm::vec3& right,
|
||||||
const glm::vec3& up,
|
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 page = 0;
|
||||||
uint next = MAX_CODEPAGES;
|
uint next = MAX_CODEPAGES;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
|
bool hasLines = false;
|
||||||
|
|
||||||
do {
|
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)) {
|
if (!font.isPrintableChar(c)) {
|
||||||
x++;
|
x++;
|
||||||
continue;
|
continue;
|
||||||
@ -109,7 +135,7 @@ static inline void draw_text(
|
|||||||
if (charpage == page){
|
if (charpage == page){
|
||||||
batch.texture(font.getPage(charpage));
|
batch.texture(font.getPage(charpage));
|
||||||
draw_glyph(
|
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){
|
else if (charpage > page && charpage < next){
|
||||||
@ -121,6 +147,31 @@ static inline void draw_text(
|
|||||||
next = MAX_CODEPAGES;
|
next = MAX_CODEPAGES;
|
||||||
x = 0;
|
x = 0;
|
||||||
} while (page < MAX_CODEPAGES);
|
} 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 {
|
const Texture* Font::getPage(int charpage) const {
|
||||||
@ -135,20 +186,30 @@ const Texture* Font::getPage(int charpage) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Font::draw(
|
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 {
|
) const {
|
||||||
draw_text(
|
draw_text(
|
||||||
*this, batch, text,
|
*this, batch, text,
|
||||||
glm::vec3(x, y, 0),
|
glm::vec3(x, y, 0),
|
||||||
glm::vec3(glyphInterval*scale, 0, 0),
|
glm::vec3(glyphInterval*scale, 0, 0),
|
||||||
glm::vec3(0, lineHeight*scale, 0),
|
glm::vec3(0, lineHeight*scale, 0),
|
||||||
glyphInterval/static_cast<float>(lineHeight)
|
glyphInterval/static_cast<float>(lineHeight),
|
||||||
|
styles,
|
||||||
|
styleMapOffset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::draw(
|
void Font::draw(
|
||||||
Batch3D& batch,
|
Batch3D& batch,
|
||||||
std::wstring_view text,
|
std::wstring_view text,
|
||||||
|
const FontStylesScheme* styles,
|
||||||
|
size_t styleMapOffset,
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::vec3& right,
|
const glm::vec3& right,
|
||||||
const glm::vec3& up
|
const glm::vec3& up
|
||||||
@ -157,6 +218,8 @@ void Font::draw(
|
|||||||
*this, batch, text, pos,
|
*this, batch, text, pos,
|
||||||
right * static_cast<float>(glyphInterval),
|
right * static_cast<float>(glyphInterval),
|
||||||
up * static_cast<float>(lineHeight),
|
up * static_cast<float>(lineHeight),
|
||||||
glyphInterval/static_cast<float>(lineHeight)
|
glyphInterval/static_cast<float>(lineHeight),
|
||||||
|
styles,
|
||||||
|
styleMapOffset
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,10 +11,33 @@ class Batch2D;
|
|||||||
class Batch3D;
|
class Batch3D;
|
||||||
class Camera;
|
class Camera;
|
||||||
|
|
||||||
enum class FontStyle {
|
struct FontStyle {
|
||||||
none,
|
bool bold = false;
|
||||||
shadow,
|
bool italic = false;
|
||||||
outline
|
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<FontStyle> palette;
|
||||||
|
std::vector<ubyte> map;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Font {
|
class Font {
|
||||||
@ -46,11 +69,21 @@ public:
|
|||||||
/// @param codepoint character unicode codepoint
|
/// @param codepoint character unicode codepoint
|
||||||
bool isPrintableChar(uint codepoint) const;
|
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(
|
void draw(
|
||||||
Batch3D& batch,
|
Batch3D& batch,
|
||||||
std::wstring_view text,
|
std::wstring_view text,
|
||||||
|
const FontStylesScheme* styles,
|
||||||
|
size_t styleMapOffset,
|
||||||
const glm::vec3& pos,
|
const glm::vec3& pos,
|
||||||
const glm::vec3& right={1, 0, 0},
|
const glm::vec3& right={1, 0, 0},
|
||||||
const glm::vec3& up={0, 1, 0}
|
const glm::vec3& up={0, 1, 0}
|
||||||
|
|||||||
@ -65,12 +65,7 @@ void TextsRenderer::renderNote(
|
|||||||
xvec *= 1.0f + scale;
|
xvec *= 1.0f + scale;
|
||||||
yvec *= 1.0f + scale;
|
yvec *= 1.0f + scale;
|
||||||
}
|
}
|
||||||
if (preset.displayMode != NoteDisplayMode::PROJECTED) {
|
if (preset.displayMode == NoteDisplayMode::PROJECTED) {
|
||||||
if (!frustum.isBoxVisible(pos - xvec * (width * 0.5f),
|
|
||||||
pos + xvec * (width * 0.5f))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
float scale = 1.0f;
|
float scale = 1.0f;
|
||||||
if (glm::abs(preset.perspective) > 0.0001f) {
|
if (glm::abs(preset.perspective) > 0.0001f) {
|
||||||
float scale2 = scale /
|
float scale2 = scale /
|
||||||
@ -99,12 +94,17 @@ void TextsRenderer::renderNote(
|
|||||||
|
|
||||||
pos = screenPos / screenPos.w;
|
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;
|
auto color = preset.color;
|
||||||
batch.setColor(glm::vec4(color.r, color.g, color.b, color.a * opacity));
|
batch.setColor(glm::vec4(color.r, color.g, color.b, color.a * opacity));
|
||||||
font.draw(
|
font.draw(
|
||||||
batch,
|
batch,
|
||||||
text,
|
text,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
pos - xvec * (width * 0.5f) * preset.scale,
|
pos - xvec * (width * 0.5f) * preset.scale,
|
||||||
xvec * preset.scale,
|
xvec * preset.scale,
|
||||||
yvec * preset.scale
|
yvec * preset.scale
|
||||||
|
|||||||
@ -197,18 +197,18 @@ void GUI::act(float delta, const Viewport& vp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::draw(const DrawContext* pctx, Assets* assets) {
|
void GUI::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
auto& viewport = pctx->getViewport();
|
auto& viewport = pctx.getViewport();
|
||||||
glm::vec2 wsize = viewport.size();
|
glm::vec2 wsize = viewport.size();
|
||||||
|
|
||||||
menu->setPos((wsize - menu->getSize()) / 2.0f);
|
menu->setPos((wsize - menu->getSize()) / 2.0f);
|
||||||
uicamera->setFov(wsize.y);
|
uicamera->setFov(wsize.y);
|
||||||
|
|
||||||
auto uishader = assets->get<Shader>("ui");
|
auto uishader = assets.get<Shader>("ui");
|
||||||
uishader->use();
|
uishader->use();
|
||||||
uishader->uniformMatrix("u_projview", uicamera->getProjView());
|
uishader->uniformMatrix("u_projview", uicamera->getProjView());
|
||||||
|
|
||||||
pctx->getBatch2D()->begin();
|
pctx.getBatch2D()->begin();
|
||||||
container->draw(pctx, assets);
|
container->draw(pctx, assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,7 @@ namespace gui {
|
|||||||
/// @brief Draw all visible elements on main container
|
/// @brief Draw all visible elements on main container
|
||||||
/// @param pctx parent graphics context
|
/// @param pctx parent graphics context
|
||||||
/// @param assets active assets storage
|
/// @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
|
/// @brief Add element to the main container
|
||||||
/// @param node UI element
|
/// @param node UI element
|
||||||
|
|||||||
@ -52,7 +52,7 @@ Button::Button(
|
|||||||
|
|
||||||
void Button::setText(std::wstring text) {
|
void Button::setText(std::wstring text) {
|
||||||
if (label) {
|
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();
|
glm::vec2 pos = calcPos();
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
batch->setColor(calcColor());
|
batch->setColor(calcColor());
|
||||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ namespace gui {
|
|||||||
|
|
||||||
class Button : public Panel {
|
class Button : public Panel {
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<Label> label = nullptr;
|
std::shared_ptr<Label> label;
|
||||||
public:
|
public:
|
||||||
Button(const std::shared_ptr<UINode>& content,
|
Button(const std::shared_ptr<UINode>& content,
|
||||||
glm::vec4 padding=glm::vec4(2.0f));
|
glm::vec4 padding=glm::vec4(2.0f));
|
||||||
@ -17,7 +17,9 @@ namespace gui {
|
|||||||
const onaction& action,
|
const onaction& action,
|
||||||
glm::vec2 size=glm::vec2(-1));
|
glm::vec2 size=glm::vec2(-1));
|
||||||
|
|
||||||
virtual void drawBackground(const DrawContext* pctx, Assets* assets) override;
|
virtual void drawBackground(
|
||||||
|
const DrawContext& pctx, const Assets& assets
|
||||||
|
) override;
|
||||||
|
|
||||||
virtual Align getTextAlign() const;
|
virtual Align getTextAlign() const;
|
||||||
virtual void setTextAlign(Align align);
|
virtual void setTextAlign(Align align);
|
||||||
|
|||||||
@ -13,12 +13,12 @@ CheckBox::CheckBox(bool checked) : UINode(glm::vec2(32.0f)), checked(checked) {
|
|||||||
setHoverColor({0.05f, 0.1f, 0.2f, 0.75f});
|
setHoverColor({0.05f, 0.1f, 0.2f, 0.75f});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckBox::draw(const DrawContext* pctx, Assets*) {
|
void CheckBox::draw(const DrawContext& pctx, const Assets&) {
|
||||||
if (supplier) {
|
if (supplier) {
|
||||||
checked = supplier();
|
checked = supplier();
|
||||||
}
|
}
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
batch->setColor(checked ? checkColor : calcColor());
|
batch->setColor(checked ? checkColor : calcColor());
|
||||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace gui {
|
|||||||
public:
|
public:
|
||||||
CheckBox(bool checked=false);
|
CheckBox(bool checked=false);
|
||||||
|
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) override;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
|
|
||||||
virtual void mouseRelease(GUI*, int x, int y) override;
|
virtual void mouseRelease(GUI*, int x, int y) override;
|
||||||
|
|
||||||
|
|||||||
@ -17,11 +17,19 @@ Container::~Container() {
|
|||||||
Container::clear();
|
Container::clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> Container::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
|
std::shared_ptr<UINode> Container::getAt(
|
||||||
|
const glm::vec2& pos, const std::shared_ptr<UINode>& self
|
||||||
|
) {
|
||||||
if (!isInteractive() || !isEnabled()) {
|
if (!isInteractive() || !isEnabled()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (!isInside(pos)) return nullptr;
|
if (!isInside(pos)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
int diff = (actualLength-size.y);
|
||||||
|
if (scrollable && diff > 0 && pos.x > calcPos().x + getSize().x - scrollBarWidth) {
|
||||||
|
return UINode::getAt(pos, self);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = nodes.size()-1; i >= 0; i--) {
|
for (int i = nodes.size()-1; i >= 0; i--) {
|
||||||
auto& node = nodes[i];
|
auto& node = nodes[i];
|
||||||
@ -35,6 +43,35 @@ std::shared_ptr<UINode> Container::getAt(glm::vec2 pos, std::shared_ptr<UINode>
|
|||||||
return UINode::getAt(pos, self);
|
return UINode::getAt(pos, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Container::mouseMove(GUI* gui, int x, int y) {
|
||||||
|
UINode::mouseMove(gui, x, y);
|
||||||
|
if (!scrollable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto pos = calcPos();
|
||||||
|
x -= pos.x;
|
||||||
|
y -= pos.y;
|
||||||
|
if (prevScrollY == -1) {
|
||||||
|
if (x >= size.x - scrollBarWidth) {
|
||||||
|
prevScrollY = y;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int diff = (actualLength-size.y);
|
||||||
|
if (diff > 0) {
|
||||||
|
scroll -= (y - prevScrollY) / static_cast<float>(size.y) * actualLength;
|
||||||
|
scroll = -glm::min(
|
||||||
|
glm::max(static_cast<float>(-scroll), 0.0f), actualLength - size.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
prevScrollY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Container::mouseRelease(GUI* gui, int x, int y) {
|
||||||
|
UINode::mouseRelease(gui, x, y);
|
||||||
|
prevScrollY = -1;
|
||||||
|
}
|
||||||
|
|
||||||
void Container::act(float delta) {
|
void Container::act(float delta) {
|
||||||
for (const auto& node : nodes) {
|
for (const auto& node : nodes) {
|
||||||
if (node->isVisible()) {
|
if (node->isVisible()) {
|
||||||
@ -80,38 +117,50 @@ void Container::setScrollable(bool flag) {
|
|||||||
scrollable = flag;
|
scrollable = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::draw(const DrawContext* pctx, Assets* assets) {
|
void Container::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
glm::vec2 size = getSize();
|
glm::vec2 size = getSize();
|
||||||
drawBackground(pctx, assets);
|
drawBackground(pctx, assets);
|
||||||
|
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
if (!nodes.empty()) {
|
if (!nodes.empty()) {
|
||||||
batch->flush();
|
batch->flush();
|
||||||
DrawContext ctx = pctx->sub();
|
DrawContext ctx = pctx.sub();
|
||||||
ctx.setScissors(glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y)));
|
ctx.setScissors(glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y)));
|
||||||
for (const auto& node : nodes) {
|
for (const auto& node : nodes) {
|
||||||
if (node->isVisible())
|
if (node->isVisible())
|
||||||
node->draw(pctx, assets);
|
node->draw(pctx, assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int diff = (actualLength-size.y);
|
||||||
|
if (scrollable && diff > 0) {
|
||||||
|
int h = glm::max(size.y / actualLength * size.y, scrollBarWidth / 2.0f);
|
||||||
|
batch->untexture();
|
||||||
|
batch->setColor(glm::vec4(1, 1, 1, 0.3f));
|
||||||
|
batch->rect(
|
||||||
|
pos.x + size.x - scrollBarWidth,
|
||||||
|
pos.y - scroll / static_cast<float>(diff) * (size.y - h),
|
||||||
|
scrollBarWidth, h
|
||||||
|
);
|
||||||
|
}
|
||||||
batch->flush();
|
batch->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::drawBackground(const DrawContext* pctx, Assets*) {
|
void Container::drawBackground(const DrawContext& pctx, const Assets&) {
|
||||||
glm::vec4 color = calcColor();
|
glm::vec4 color = calcColor();
|
||||||
if (color.a <= 0.001f)
|
if (color.a <= 0.001f)
|
||||||
return;
|
return;
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
|
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
batch->setColor(color);
|
batch->setColor(color);
|
||||||
batch->rect(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y));
|
batch->rect(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::add(const std::shared_ptr<UINode> &node) {
|
void Container::add(const std::shared_ptr<UINode>& node) {
|
||||||
nodes.push_back(node);
|
nodes.push_back(node);
|
||||||
node->setParent(this);
|
node->setParent(this);
|
||||||
node->reposition();
|
node->reposition();
|
||||||
|
|||||||
@ -7,23 +7,29 @@
|
|||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
class Container : public UINode {
|
class Container : public UINode {
|
||||||
|
int prevScrollY = -1;
|
||||||
protected:
|
protected:
|
||||||
std::vector<std::shared_ptr<UINode>> nodes;
|
std::vector<std::shared_ptr<UINode>> nodes;
|
||||||
std::vector<IntervalEvent> intervalEvents;
|
std::vector<IntervalEvent> intervalEvents;
|
||||||
int scroll = 0;
|
int scroll = 0;
|
||||||
int scrollStep = 40;
|
int scrollStep = 40;
|
||||||
|
int scrollBarWidth = 10;
|
||||||
int actualLength = 0;
|
int actualLength = 0;
|
||||||
bool scrollable = true;
|
bool scrollable = true;
|
||||||
|
|
||||||
|
bool isScrolling() {
|
||||||
|
return prevScrollY != -1;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
Container(glm::vec2 size);
|
Container(glm::vec2 size);
|
||||||
virtual ~Container();
|
virtual ~Container();
|
||||||
|
|
||||||
virtual void act(float delta) override;
|
virtual void act(float delta) override;
|
||||||
virtual void drawBackground(const DrawContext* pctx, Assets* assets);
|
virtual void drawBackground(const DrawContext& pctx, const Assets& assets);
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) override;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
|
virtual std::shared_ptr<UINode> getAt(const glm::vec2& pos, const std::shared_ptr<UINode>& self) override;
|
||||||
virtual void add(const std::shared_ptr<UINode> &node);
|
virtual void add(const std::shared_ptr<UINode>& node);
|
||||||
virtual void add(const std::shared_ptr<UINode> &node, glm::vec2 pos);
|
virtual void add(const std::shared_ptr<UINode>& node, glm::vec2 pos);
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
virtual void remove(const std::shared_ptr<UINode>& node);
|
virtual void remove(const std::shared_ptr<UINode>& node);
|
||||||
virtual void remove(const std::string& id);
|
virtual void remove(const std::string& id);
|
||||||
@ -36,6 +42,9 @@ namespace gui {
|
|||||||
virtual void setScrollStep(int step);
|
virtual void setScrollStep(int step);
|
||||||
virtual void refresh() override;
|
virtual void refresh() override;
|
||||||
|
|
||||||
|
virtual void mouseMove(GUI*, int x, int y) override;
|
||||||
|
virtual void mouseRelease(GUI*, int x, int y) override;
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<UINode>>& getNodes() const;
|
const std::vector<std::shared_ptr<UINode>>& getNodes() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,21 +15,21 @@ Image::Image(std::string texture, glm::vec2 size) : UINode(size), texture(std::m
|
|||||||
setInteractive(false);
|
setInteractive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::draw(const DrawContext* pctx, Assets* assets) {
|
void Image::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
|
|
||||||
Texture* texture = nullptr;
|
Texture* texture = nullptr;
|
||||||
auto separator = this->texture.find(':');
|
auto separator = this->texture.find(':');
|
||||||
if (separator == std::string::npos) {
|
if (separator == std::string::npos) {
|
||||||
texture = assets->get<Texture>(this->texture);
|
texture = assets.get<Texture>(this->texture);
|
||||||
batch->texture(texture);
|
batch->texture(texture);
|
||||||
if (texture && autoresize) {
|
if (texture && autoresize) {
|
||||||
setSize(glm::vec2(texture->getWidth(), texture->getHeight()));
|
setSize(glm::vec2(texture->getWidth(), texture->getHeight()));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto atlasName = this->texture.substr(0, separator);
|
auto atlasName = this->texture.substr(0, separator);
|
||||||
if (auto atlas = assets->get<Atlas>(atlasName)) {
|
if (auto atlas = assets.get<Atlas>(atlasName)) {
|
||||||
if (auto region = atlas->getIf(this->texture.substr(separator+1))) {
|
if (auto region = atlas->getIf(this->texture.substr(separator+1))) {
|
||||||
texture = atlas->getTexture();
|
texture = atlas->getTexture();
|
||||||
batch->texture(atlas->getTexture());
|
batch->texture(atlas->getTexture());
|
||||||
|
|||||||
@ -10,7 +10,7 @@ namespace gui {
|
|||||||
public:
|
public:
|
||||||
Image(std::string texture, glm::vec2 size=glm::vec2(32,32));
|
Image(std::string texture, glm::vec2 size=glm::vec2(32,32));
|
||||||
|
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) override;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
|
|
||||||
virtual void setAutoResize(bool flag);
|
virtual void setAutoResize(bool flag);
|
||||||
virtual bool isAutoResize() const;
|
virtual bool isAutoResize() const;
|
||||||
|
|||||||
@ -9,15 +9,15 @@ using namespace gui;
|
|||||||
|
|
||||||
InputBindBox::InputBindBox(Binding& binding, glm::vec4 padding)
|
InputBindBox::InputBindBox(Binding& binding, glm::vec4 padding)
|
||||||
: Panel(glm::vec2(100,32), padding, 0),
|
: Panel(glm::vec2(100,32), padding, 0),
|
||||||
binding(binding) {
|
binding(binding),
|
||||||
label = std::make_shared<Label>(L"");
|
label(std::make_shared<Label>(L"")) {
|
||||||
add(label);
|
add(label);
|
||||||
setScrollable(false);
|
setScrollable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputBindBox::drawBackground(const DrawContext* pctx, Assets*) {
|
void InputBindBox::drawBackground(const DrawContext& pctx, const Assets&) {
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
batch->setColor(isFocused() ? focusedColor : calcColor());
|
batch->setColor(isFocused() ? focusedColor : calcColor());
|
||||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||||
|
|||||||
@ -13,7 +13,10 @@ namespace gui {
|
|||||||
Binding& binding;
|
Binding& binding;
|
||||||
public:
|
public:
|
||||||
InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f));
|
InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f));
|
||||||
virtual void drawBackground(const DrawContext* pctx, Assets* assets) override;
|
|
||||||
|
virtual void drawBackground(
|
||||||
|
const DrawContext& pctx, const Assets& assets
|
||||||
|
) override;
|
||||||
|
|
||||||
virtual void clicked(GUI*, mousecode button) override;
|
virtual void clicked(GUI*, mousecode button) override;
|
||||||
virtual void keyPressed(keycode key) override;
|
virtual void keyPressed(keycode key) override;
|
||||||
|
|||||||
@ -54,7 +54,7 @@ InventoryBuilder::InventoryBuilder() {
|
|||||||
void InventoryBuilder::addGrid(
|
void InventoryBuilder::addGrid(
|
||||||
int cols, int count,
|
int cols, int count,
|
||||||
glm::vec2 pos,
|
glm::vec2 pos,
|
||||||
int padding,
|
glm::vec4 padding,
|
||||||
bool addpanel,
|
bool addpanel,
|
||||||
const SlotLayout& slotLayout
|
const SlotLayout& slotLayout
|
||||||
) {
|
) {
|
||||||
@ -63,8 +63,8 @@ void InventoryBuilder::addGrid(
|
|||||||
|
|
||||||
int rows = ceildiv(count, cols);
|
int rows = ceildiv(count, cols);
|
||||||
|
|
||||||
uint width = cols * (slotSize + interval) - interval + padding*2;
|
uint width = cols * (slotSize + interval) - interval + padding.x + padding.z;
|
||||||
uint height = rows * (slotSize + interval) - interval + padding*2;
|
uint height = rows * (slotSize + interval) - interval + padding.y + padding.w;
|
||||||
|
|
||||||
glm::vec2 vsize = view->getSize();
|
glm::vec2 vsize = view->getSize();
|
||||||
if (pos.x + width > vsize.x) {
|
if (pos.x + width > vsize.x) {
|
||||||
@ -87,8 +87,8 @@ void InventoryBuilder::addGrid(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
glm::vec2 position (
|
glm::vec2 position (
|
||||||
col * (slotSize + interval) + padding,
|
col * (slotSize + interval) + padding.x,
|
||||||
row * (slotSize + interval) + padding
|
row * (slotSize + interval) + padding.y
|
||||||
);
|
);
|
||||||
auto builtSlot = slotLayout;
|
auto builtSlot = slotLayout;
|
||||||
builtSlot.index = row * cols + col;
|
builtSlot.index = row * cols + col;
|
||||||
@ -115,7 +115,7 @@ SlotView::SlotView(
|
|||||||
setTooltipDelay(0.0f);
|
setTooltipDelay(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlotView::draw(const DrawContext* pctx, Assets* assets) {
|
void SlotView::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
if (bound == nullptr) {
|
if (bound == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
color = glm::vec4(1, 1, 1, 0.2f);
|
color = glm::vec4(1, 1, 1, 0.2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->setColor(color);
|
batch->setColor(color);
|
||||||
if (color.a > 0.0) {
|
if (color.a > 0.0) {
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
@ -157,7 +157,7 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
|
|
||||||
batch->setColor(glm::vec4(1.0f));
|
batch->setColor(glm::vec4(1.0f));
|
||||||
|
|
||||||
auto previews = assets->get<Atlas>("block-previews");
|
auto previews = assets.get<Atlas>("block-previews");
|
||||||
auto indices = content->getIndices();
|
auto indices = content->getIndices();
|
||||||
|
|
||||||
auto& item = indices->items.require(stack.getItemId());
|
auto& item = indices->items.require(stack.getItemId());
|
||||||
@ -176,7 +176,7 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
}
|
}
|
||||||
case ItemIconType::SPRITE: {
|
case ItemIconType::SPRITE: {
|
||||||
auto textureRegion =
|
auto textureRegion =
|
||||||
util::get_texture_region(*assets, item.icon, "blocks:notfound");
|
util::get_texture_region(assets, item.icon, "blocks:notfound");
|
||||||
|
|
||||||
batch->texture(textureRegion.texture);
|
batch->texture(textureRegion.texture);
|
||||||
batch->rect(
|
batch->rect(
|
||||||
@ -187,16 +187,16 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stack.getCount() > 1) {
|
if (stack.getCount() > 1) {
|
||||||
auto font = assets->get<Font>("normal");
|
auto font = assets.get<Font>("normal");
|
||||||
std::wstring text = std::to_wstring(stack.getCount());
|
std::wstring text = std::to_wstring(stack.getCount());
|
||||||
|
|
||||||
int x = pos.x+slotSize-text.length()*8;
|
int x = pos.x+slotSize-text.length()*8;
|
||||||
int y = pos.y+slotSize-16;
|
int y = pos.y+slotSize-16;
|
||||||
|
|
||||||
batch->setColor({0, 0, 0, 1.0f});
|
batch->setColor({0, 0, 0, 1.0f});
|
||||||
font->draw(*batch, text, x+1, y+1);
|
font->draw(*batch, text, x+1, y+1, nullptr, 0);
|
||||||
batch->setColor(glm::vec4(1.0f));
|
batch->setColor(glm::vec4(1.0f));
|
||||||
font->draw(*batch, text, x, y);
|
font->draw(*batch, text, x, y, nullptr, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -64,7 +64,7 @@ namespace gui {
|
|||||||
public:
|
public:
|
||||||
SlotView(SlotLayout layout);
|
SlotView(SlotLayout layout);
|
||||||
|
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) override;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
|
|
||||||
void setHighlighted(bool flag);
|
void setHighlighted(bool flag);
|
||||||
bool isHighlighted() const;
|
bool isHighlighted() const;
|
||||||
@ -136,7 +136,7 @@ namespace gui {
|
|||||||
void addGrid(
|
void addGrid(
|
||||||
int cols, int count,
|
int cols, int count,
|
||||||
glm::vec2 pos,
|
glm::vec2 pos,
|
||||||
int padding,
|
glm::vec4 padding,
|
||||||
bool addpanel,
|
bool addpanel,
|
||||||
const SlotLayout& slotLayout
|
const SlotLayout& slotLayout
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include "graphics/core/Font.hpp"
|
#include "graphics/core/Font.hpp"
|
||||||
#include "assets/Assets.hpp"
|
#include "assets/Assets.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
|
#include "../markdown.hpp"
|
||||||
|
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
@ -66,6 +67,8 @@ Label::Label(const std::wstring& text, std::string fontName)
|
|||||||
cache.update(this->text, multiline, textWrap);
|
cache.update(this->text, multiline, textWrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label::~Label() = default;
|
||||||
|
|
||||||
glm::vec2 Label::calcSize() {
|
glm::vec2 Label::calcSize() {
|
||||||
auto font = cache.font;
|
auto font = cache.font;
|
||||||
uint lineHeight = font->getLineHeight();
|
uint lineHeight = font->getLineHeight();
|
||||||
@ -78,11 +81,16 @@ glm::vec2 Label::calcSize() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Label::setText(const std::wstring& text) {
|
void Label::setText(std::wstring text) {
|
||||||
|
if (markup == "md") {
|
||||||
|
auto [processedText, styles] = markdown::process(text, true);
|
||||||
|
text = std::move(processedText);
|
||||||
|
setStyles(std::move(styles));
|
||||||
|
}
|
||||||
if (text == this->text && !cache.resetFlag) {
|
if (text == this->text && !cache.resetFlag) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this->text = text;
|
this->text = std::move(text);
|
||||||
cache.update(this->text, multiline, textWrap);
|
cache.update(this->text, multiline, textWrap);
|
||||||
|
|
||||||
if (cache.font && autoresize) {
|
if (cache.font && autoresize) {
|
||||||
@ -156,9 +164,9 @@ uint Label::getLinesNumber() const {
|
|||||||
return cache.lines.size();
|
return cache.lines.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Label::draw(const DrawContext* pctx, Assets* assets) {
|
void Label::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
auto font = assets->get<Font>(fontName);
|
auto font = assets.get<Font>(fontName);
|
||||||
cache.prepare(font, static_cast<size_t>(glm::abs(getSize().x)));
|
cache.prepare(font, static_cast<size_t>(glm::abs(getSize().x)));
|
||||||
|
|
||||||
if (supplier) {
|
if (supplier) {
|
||||||
@ -201,10 +209,10 @@ void Label::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
if (i < cache.lines.size()-1) {
|
if (i < cache.lines.size()-1) {
|
||||||
view = std::wstring_view(text.c_str()+offset, cache.lines.at(i+1).offset-offset);
|
view = std::wstring_view(text.c_str()+offset, cache.lines.at(i+1).offset-offset);
|
||||||
}
|
}
|
||||||
font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight);
|
font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight, styles.get(), offset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
font->draw(*batch, text, pos.x, pos.y);
|
font->draw(*batch, text, pos.x, pos.y, styles.get(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,3 +247,16 @@ void Label::setTextWrapping(bool flag) {
|
|||||||
bool Label::isTextWrapping() const {
|
bool Label::isTextWrapping() const {
|
||||||
return textWrap;
|
return textWrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Label::setMarkup(std::string_view lang) {
|
||||||
|
markup = lang;
|
||||||
|
setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& Label::getMarkup() const {
|
||||||
|
return markup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Label::setStyles(std::unique_ptr<FontStylesScheme> styles) {
|
||||||
|
this->styles = std::move(styles);
|
||||||
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "UINode.hpp"
|
#include "UINode.hpp"
|
||||||
|
|
||||||
class Font;
|
class Font;
|
||||||
|
struct FontStylesScheme;
|
||||||
|
|
||||||
namespace gui {
|
namespace gui {
|
||||||
struct LineScheme {
|
struct LineScheme {
|
||||||
@ -51,11 +52,18 @@ namespace gui {
|
|||||||
|
|
||||||
/// @brief Auto resize label to fit text
|
/// @brief Auto resize label to fit text
|
||||||
bool autoresize = false;
|
bool autoresize = false;
|
||||||
|
|
||||||
|
/// @brief Text markup language
|
||||||
|
std::string markup;
|
||||||
|
|
||||||
|
std::unique_ptr<FontStylesScheme> styles;
|
||||||
public:
|
public:
|
||||||
Label(const std::string& text, std::string fontName="normal");
|
Label(const std::string& text, std::string fontName="normal");
|
||||||
Label(const std::wstring& text, std::string fontName="normal");
|
Label(const std::wstring& text, std::string fontName="normal");
|
||||||
|
|
||||||
virtual void setText(const std::wstring& text);
|
virtual ~Label();
|
||||||
|
|
||||||
|
virtual void setText(std::wstring text);
|
||||||
const std::wstring& getText() const;
|
const std::wstring& getText() const;
|
||||||
|
|
||||||
virtual void setFontName(std::string name);
|
virtual void setFontName(std::string name);
|
||||||
@ -95,7 +103,7 @@ namespace gui {
|
|||||||
virtual uint getLinesNumber() const;
|
virtual uint getLinesNumber() const;
|
||||||
virtual bool isFakeLine(size_t line) const;
|
virtual bool isFakeLine(size_t line) const;
|
||||||
|
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) override;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
|
|
||||||
virtual void textSupplier(wstringsupplier supplier);
|
virtual void textSupplier(wstringsupplier supplier);
|
||||||
|
|
||||||
@ -107,5 +115,10 @@ namespace gui {
|
|||||||
|
|
||||||
virtual void setTextWrapping(bool flag);
|
virtual void setTextWrapping(bool flag);
|
||||||
virtual bool isTextWrapping() const;
|
virtual bool isTextWrapping() const;
|
||||||
|
|
||||||
|
virtual void setMarkup(std::string_view lang);
|
||||||
|
virtual const std::string& getMarkup() const;
|
||||||
|
|
||||||
|
virtual void setStyles(std::unique_ptr<FontStylesScheme> styles);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
namespace gui {
|
namespace gui {
|
||||||
struct Page {
|
struct Page {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::shared_ptr<UINode> panel = nullptr;
|
std::shared_ptr<UINode> panel;
|
||||||
};
|
};
|
||||||
|
|
||||||
using page_loader_func = std::function<std::shared_ptr<UINode>(const std::string& name)>;
|
using page_loader_func = std::function<std::shared_ptr<UINode>(const std::string& name)>;
|
||||||
@ -31,13 +31,13 @@ namespace gui {
|
|||||||
/// @param history previous page will not be saved in history if false
|
/// @param history previous page will not be saved in history if false
|
||||||
void setPage(const std::string &name, bool history=true);
|
void setPage(const std::string &name, bool history=true);
|
||||||
void setPage(Page page, bool history=true);
|
void setPage(Page page, bool history=true);
|
||||||
void addPage(const std::string& name, const std::shared_ptr<UINode> &panel);
|
void addPage(const std::string& name, const std::shared_ptr<UINode>& panel);
|
||||||
std::shared_ptr<UINode> fetchPage(const std::string& name);
|
std::shared_ptr<UINode> fetchPage(const std::string& name);
|
||||||
|
|
||||||
/// @brief Add page supplier used if page is not found
|
/// @brief Add page supplier used if page is not found
|
||||||
/// @param name page name
|
/// @param name page name
|
||||||
/// @param pageSupplier page supplier function
|
/// @param pageSupplier page supplier function
|
||||||
void addSupplier(const std::string &name, const supplier<std::shared_ptr<UINode>> &pageSupplier);
|
void addSupplier(const std::string& name, const supplier<std::shared_ptr<UINode>>& pageSupplier);
|
||||||
|
|
||||||
/// @brief Page loader is called if accessed page is not found
|
/// @brief Page loader is called if accessed page is not found
|
||||||
void setPageLoader(page_loader_func loader);
|
void setPageLoader(page_loader_func loader);
|
||||||
|
|||||||
@ -23,7 +23,7 @@ namespace gui {
|
|||||||
virtual void setOrientation(Orientation orientation);
|
virtual void setOrientation(Orientation orientation);
|
||||||
Orientation getOrientation() const;
|
Orientation getOrientation() const;
|
||||||
|
|
||||||
virtual void add(const std::shared_ptr<UINode> &node) override;
|
virtual void add(const std::shared_ptr<UINode>& node) override;
|
||||||
|
|
||||||
virtual void refresh() override;
|
virtual void refresh() override;
|
||||||
virtual void fullRefresh() override;
|
virtual void fullRefresh() override;
|
||||||
|
|||||||
@ -14,9 +14,9 @@ void Plotter::act(float delta) {
|
|||||||
points[index % dmwidth] = std::min(value, dmheight);
|
points[index % dmwidth] = std::min(value, dmheight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plotter::draw(const DrawContext* pctx, Assets* assets) {
|
void Plotter::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
batch->lineWidth(1);
|
batch->lineWidth(1);
|
||||||
for (int i = index+1; i < index+dmwidth; i++) {
|
for (int i = index+1; i < index+dmwidth; i++) {
|
||||||
@ -37,7 +37,7 @@ void Plotter::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int current_point = static_cast<int>(points[index % dmwidth]);
|
int current_point = static_cast<int>(points[index % dmwidth]);
|
||||||
auto font = assets->get<Font>("normal");
|
auto font = assets.get<Font>("normal");
|
||||||
for (int y = 0; y < dmheight; y += labelsInterval) {
|
for (int y = 0; y < dmheight; y += labelsInterval) {
|
||||||
std::wstring string;
|
std::wstring string;
|
||||||
if (current_point/16 == y/labelsInterval) {
|
if (current_point/16 == y/labelsInterval) {
|
||||||
@ -47,6 +47,13 @@ void Plotter::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
batch->setColor({1,1,1,0.2f});
|
batch->setColor({1,1,1,0.2f});
|
||||||
string = util::to_wstring(y / multiplier, 3);
|
string = util::to_wstring(y / multiplier, 3);
|
||||||
}
|
}
|
||||||
font->draw(*batch, string, pos.x+dmwidth+2, pos.y+dmheight-y-labelsInterval);
|
font->draw(
|
||||||
|
*batch,
|
||||||
|
string,
|
||||||
|
pos.x + dmwidth + 2,
|
||||||
|
pos.y + dmheight - y - labelsInterval,
|
||||||
|
nullptr,
|
||||||
|
0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,6 +29,6 @@ namespace gui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void act(float delta) override;
|
void act(float delta) override;
|
||||||
void draw(const DrawContext* pctx, Assets* assets) override;
|
void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Label.hpp"
|
#include "Label.hpp"
|
||||||
|
#include "devtools/syntax_highlighting.hpp"
|
||||||
#include "graphics/core/DrawContext.hpp"
|
#include "graphics/core/DrawContext.hpp"
|
||||||
#include "graphics/core/Batch2D.hpp"
|
#include "graphics/core/Batch2D.hpp"
|
||||||
#include "graphics/core/Font.hpp"
|
#include "graphics/core/Font.hpp"
|
||||||
@ -12,6 +13,7 @@
|
|||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "window/Events.hpp"
|
#include "window/Events.hpp"
|
||||||
#include "window/Window.hpp"
|
#include "window/Window.hpp"
|
||||||
|
#include "../markdown.hpp"
|
||||||
|
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
@ -46,10 +48,10 @@ TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
|||||||
scrollStep = 0;
|
scrollStep = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::draw(const DrawContext* pctx, Assets* assets) {
|
void TextBox::draw(const DrawContext& pctx, const Assets& assets) {
|
||||||
Container::draw(pctx, assets);
|
Container::draw(pctx, assets);
|
||||||
|
|
||||||
font = assets->get<Font>(label->getFontName());
|
font = assets.get<Font>(label->getFontName());
|
||||||
|
|
||||||
if (!isFocused()) {
|
if (!isFocused()) {
|
||||||
return;
|
return;
|
||||||
@ -57,39 +59,67 @@ void TextBox::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
glm::vec2 size = getSize();
|
glm::vec2 size = getSize();
|
||||||
|
|
||||||
auto subctx = pctx->sub();
|
auto subctx = pctx.sub();
|
||||||
subctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y));
|
subctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y));
|
||||||
|
|
||||||
const int lineHeight = font->getLineHeight() * label->getLineInterval();
|
const int lineHeight = font->getLineHeight() * label->getLineInterval();
|
||||||
glm::vec2 lcoord = label->calcPos();
|
glm::vec2 lcoord = label->calcPos();
|
||||||
lcoord.y -= 2;
|
lcoord.y -= 2;
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
|
batch->setColor(glm::vec4(1.0f));
|
||||||
if (editable && int((Window::time() - caretLastMove) * 2) % 2 == 0) {
|
if (editable && int((Window::time() - caretLastMove) * 2) % 2 == 0) {
|
||||||
uint line = label->getLineByTextIndex(caret);
|
uint line = label->getLineByTextIndex(caret);
|
||||||
uint lcaret = caret - label->getTextLineOffset(line);
|
uint lcaret = caret - label->getTextLineOffset(line);
|
||||||
batch->setColor(glm::vec4(1.0f));
|
|
||||||
|
|
||||||
int width = font->calcWidth(input, lcaret);
|
int width = font->calcWidth(input, lcaret);
|
||||||
batch->rect(lcoord.x + width, lcoord.y+label->getLineYOffset(line), 2, lineHeight);
|
batch->rect(
|
||||||
|
lcoord.x + width,
|
||||||
|
lcoord.y + label->getLineYOffset(line),
|
||||||
|
2,
|
||||||
|
lineHeight
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (selectionStart != selectionEnd) {
|
if (selectionStart != selectionEnd) {
|
||||||
|
auto selectionCtx = subctx.sub(batch);
|
||||||
|
selectionCtx.setBlendMode(BlendMode::addition);
|
||||||
|
|
||||||
uint startLine = label->getLineByTextIndex(selectionStart);
|
uint startLine = label->getLineByTextIndex(selectionStart);
|
||||||
uint endLine = label->getLineByTextIndex(selectionEnd);
|
uint endLine = label->getLineByTextIndex(selectionEnd);
|
||||||
|
|
||||||
batch->setColor(glm::vec4(0.8f, 0.9f, 1.0f, 0.25f));
|
batch->setColor(glm::vec4(0.8f, 0.9f, 1.0f, 0.25f));
|
||||||
int start = font->calcWidth(input, selectionStart-label->getTextLineOffset(startLine));
|
int start = font->calcWidth(
|
||||||
int end = font->calcWidth(input, selectionEnd-label->getTextLineOffset(endLine));
|
input, selectionStart - label->getTextLineOffset(startLine)
|
||||||
|
);
|
||||||
|
int end = font->calcWidth(
|
||||||
|
input, selectionEnd - label->getTextLineOffset(endLine)
|
||||||
|
);
|
||||||
int lineY = label->getLineYOffset(startLine);
|
int lineY = label->getLineYOffset(startLine);
|
||||||
|
|
||||||
if (startLine == endLine) {
|
if (startLine == endLine) {
|
||||||
batch->rect(lcoord.x + start, lcoord.y+lineY, end-start, lineHeight);
|
batch->rect(
|
||||||
|
lcoord.x + start, lcoord.y + lineY, end - start, lineHeight
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
batch->rect(lcoord.x + start, lcoord.y+lineY, label->getSize().x-start-padding.z-padding.x-2, lineHeight);
|
batch->rect(
|
||||||
for (uint i = startLine+1; i < endLine; i++) {
|
lcoord.x + start,
|
||||||
batch->rect(lcoord.x, lcoord.y+label->getLineYOffset(i), label->getSize().x-padding.z-padding.x-2, lineHeight);
|
lcoord.y + lineY,
|
||||||
|
label->getSize().x - start - padding.z - padding.x - 2,
|
||||||
|
lineHeight
|
||||||
|
);
|
||||||
|
for (uint i = startLine + 1; i < endLine; i++) {
|
||||||
|
batch->rect(
|
||||||
|
lcoord.x,
|
||||||
|
lcoord.y + label->getLineYOffset(i),
|
||||||
|
label->getSize().x - padding.z - padding.x - 2,
|
||||||
|
lineHeight
|
||||||
|
);
|
||||||
}
|
}
|
||||||
batch->rect(lcoord.x, lcoord.y+label->getLineYOffset(endLine), end, lineHeight);
|
batch->rect(
|
||||||
|
lcoord.x,
|
||||||
|
lcoord.y + label->getLineYOffset(endLine),
|
||||||
|
end,
|
||||||
|
lineHeight
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,13 +162,13 @@ void TextBox::draw(const DrawContext* pctx, Assets* assets) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::drawBackground(const DrawContext* pctx, Assets*) {
|
void TextBox::drawBackground(const DrawContext& pctx, const Assets&) {
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
|
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
|
|
||||||
auto subctx = pctx->sub();
|
auto subctx = pctx.sub();
|
||||||
subctx.setScissors(glm::vec4(pos.x, pos.y-0.5, size.x, size.y+1));
|
subctx.setScissors(glm::vec4(pos.x, pos.y-0.5, size.x, size.y+1));
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
@ -162,7 +192,18 @@ void TextBox::drawBackground(const DrawContext* pctx, Assets*) {
|
|||||||
|
|
||||||
void TextBox::refreshLabel() {
|
void TextBox::refreshLabel() {
|
||||||
label->setColor(textColor * glm::vec4(input.empty() ? 0.5f : 1.0f));
|
label->setColor(textColor * glm::vec4(input.empty() ? 0.5f : 1.0f));
|
||||||
label->setText(input.empty() && !hint.empty() ? hint : getText());
|
|
||||||
|
const auto& displayText = input.empty() && !hint.empty() ? hint : getText();
|
||||||
|
if (markup == "md") {
|
||||||
|
auto [processedText, styles] = markdown::process(displayText, !focused);
|
||||||
|
label->setText(std::move(processedText));
|
||||||
|
label->setStyles(std::move(styles));
|
||||||
|
} else {
|
||||||
|
label->setText(displayText);
|
||||||
|
if (syntax.empty()) {
|
||||||
|
label->setStyles(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (showLineNumbers) {
|
if (showLineNumbers) {
|
||||||
if (lineNumbersLabel->getLinesNumber() != label->getLinesNumber()) {
|
if (lineNumbersLabel->getLinesNumber() != label->getLinesNumber()) {
|
||||||
@ -202,7 +243,8 @@ void TextBox::refreshLabel() {
|
|||||||
|
|
||||||
if (multiline && font) {
|
if (multiline && font) {
|
||||||
setScrollable(true);
|
setScrollable(true);
|
||||||
uint height = label->getLinesNumber() * font->getLineHeight() * label->getLineInterval();
|
uint height = label->getLinesNumber() * font->getLineHeight() *
|
||||||
|
label->getLineInterval();
|
||||||
label->setSize(glm::vec2(label->getSize().x, height));
|
label->setSize(glm::vec2(label->getSize().x, height));
|
||||||
actualLength = height;
|
actualLength = height;
|
||||||
} else {
|
} else {
|
||||||
@ -388,7 +430,7 @@ int TextBox::calcIndexAt(int x, int y) const {
|
|||||||
return std::min(offset+label->getTextLineOffset(line), input.length());
|
return std::min(offset+label->getTextLineOffset(line), input.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::wstring get_alphabet(wchar_t c) {
|
static inline std::wstring get_alphabet(wchar_t c) {
|
||||||
std::wstring alphabet {c};
|
std::wstring alphabet {c};
|
||||||
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
|
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
|
||||||
return L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
return L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
@ -433,7 +475,11 @@ void TextBox::click(GUI*, int x, int y) {
|
|||||||
selectionOrigin = index;
|
selectionOrigin = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::mouseMove(GUI*, int x, int y) {
|
void TextBox::mouseMove(GUI* gui, int x, int y) {
|
||||||
|
Container::mouseMove(gui, x, y);
|
||||||
|
if (isScrolling()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ptrdiff_t index = calcIndexAt(x, y);
|
ptrdiff_t index = calcIndexAt(x, y);
|
||||||
setCaret(index);
|
setCaret(index);
|
||||||
extendSelection(index);
|
extendSelection(index);
|
||||||
@ -529,10 +575,21 @@ void TextBox::stepDefaultUp(bool shiftPressed, bool breakSelection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextBox::refreshSyntax() {
|
||||||
|
if (!syntax.empty()) {
|
||||||
|
if (auto styles = devtools::syntax_highlight(
|
||||||
|
syntax, util::wstr2str_utf8(input)
|
||||||
|
)) {
|
||||||
|
label->setStyles(std::move(styles));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TextBox::onInput() {
|
void TextBox::onInput() {
|
||||||
if (subconsumer) {
|
if (subconsumer) {
|
||||||
subconsumer(input);
|
subconsumer(input);
|
||||||
}
|
}
|
||||||
|
refreshSyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextBox::performEditingKeyboardEvents(keycode key) {
|
void TextBox::performEditingKeyboardEvents(keycode key) {
|
||||||
@ -632,7 +689,9 @@ size_t TextBox::getLinePos(uint line) const {
|
|||||||
return label->getTextLineOffset(line);
|
return label->getTextLineOffset(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> TextBox::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
|
std::shared_ptr<UINode> TextBox::getAt(
|
||||||
|
const glm::vec2& pos, const std::shared_ptr<UINode>& self
|
||||||
|
) {
|
||||||
return UINode::getAt(pos, self);
|
return UINode::getAt(pos, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,6 +769,7 @@ const std::wstring& TextBox::getText() const {
|
|||||||
void TextBox::setText(const std::wstring& value) {
|
void TextBox::setText(const std::wstring& value) {
|
||||||
this->input = value;
|
this->input = value;
|
||||||
input.erase(std::remove(input.begin(), input.end(), '\r'), input.end());
|
input.erase(std::remove(input.begin(), input.end(), '\r'), input.end());
|
||||||
|
refreshSyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::wstring& TextBox::getPlaceholder() const {
|
const std::wstring& TextBox::getPlaceholder() const {
|
||||||
@ -789,3 +849,24 @@ void TextBox::setShowLineNumbers(bool flag) {
|
|||||||
bool TextBox::isShowLineNumbers() const {
|
bool TextBox::isShowLineNumbers() const {
|
||||||
return showLineNumbers;
|
return showLineNumbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextBox::setSyntax(std::string_view lang) {
|
||||||
|
syntax = lang;
|
||||||
|
if (syntax.empty()) {
|
||||||
|
label->setStyles(nullptr);
|
||||||
|
} else {
|
||||||
|
refreshSyntax();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& TextBox::getSyntax() const {
|
||||||
|
return syntax;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextBox::setMarkup(std::string_view lang) {
|
||||||
|
markup = lang;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& TextBox::getMarkup() const {
|
||||||
|
return markup;
|
||||||
|
}
|
||||||
|
|||||||
@ -56,6 +56,8 @@ namespace gui {
|
|||||||
bool editable = true;
|
bool editable = true;
|
||||||
bool autoresize = false;
|
bool autoresize = false;
|
||||||
bool showLineNumbers = false;
|
bool showLineNumbers = false;
|
||||||
|
std::string markup;
|
||||||
|
std::string syntax;
|
||||||
|
|
||||||
void stepLeft(bool shiftPressed, bool breakSelection);
|
void stepLeft(bool shiftPressed, bool breakSelection);
|
||||||
void stepRight(bool shiftPressed, bool breakSelection);
|
void stepRight(bool shiftPressed, bool breakSelection);
|
||||||
@ -84,6 +86,8 @@ namespace gui {
|
|||||||
void refreshLabel();
|
void refreshLabel();
|
||||||
|
|
||||||
void onInput();
|
void onInput();
|
||||||
|
|
||||||
|
void refreshSyntax();
|
||||||
public:
|
public:
|
||||||
TextBox(
|
TextBox(
|
||||||
std::wstring placeholder,
|
std::wstring placeholder,
|
||||||
@ -212,12 +216,20 @@ namespace gui {
|
|||||||
virtual void click(GUI*, int, int) override;
|
virtual void click(GUI*, int, int) override;
|
||||||
virtual void mouseMove(GUI*, int x, int y) override;
|
virtual void mouseMove(GUI*, int x, int y) override;
|
||||||
virtual bool isFocuskeeper() const override {return true;}
|
virtual bool isFocuskeeper() const override {return true;}
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) override;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
virtual void drawBackground(const DrawContext* pctx, Assets* assets) override;
|
virtual void drawBackground(const DrawContext& pctx, const Assets& assets) override;
|
||||||
virtual void typed(unsigned int codepoint) override;
|
virtual void typed(unsigned int codepoint) override;
|
||||||
virtual void keyPressed(keycode key) override;
|
virtual void keyPressed(keycode key) override;
|
||||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
|
virtual std::shared_ptr<UINode> getAt(
|
||||||
|
const glm::vec2& pos, const std::shared_ptr<UINode>& self
|
||||||
|
) override;
|
||||||
virtual void setOnUpPressed(const runnable &callback);
|
virtual void setOnUpPressed(const runnable &callback);
|
||||||
virtual void setOnDownPressed(const runnable &callback);
|
virtual void setOnDownPressed(const runnable &callback);
|
||||||
|
|
||||||
|
virtual void setSyntax(std::string_view lang);
|
||||||
|
virtual const std::string& getSyntax() const;
|
||||||
|
|
||||||
|
virtual void setMarkup(std::string_view lang);
|
||||||
|
virtual const std::string& getMarkup() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,12 +25,12 @@ TrackBar::TrackBar(
|
|||||||
setHoverColor(glm::vec4(0.01f, 0.02f, 0.03f, 0.5f));
|
setHoverColor(glm::vec4(0.01f, 0.02f, 0.03f, 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackBar::draw(const DrawContext* pctx, Assets*) {
|
void TrackBar::draw(const DrawContext& pctx, const Assets&) {
|
||||||
if (supplier) {
|
if (supplier) {
|
||||||
value = supplier();
|
value = supplier();
|
||||||
}
|
}
|
||||||
glm::vec2 pos = calcPos();
|
glm::vec2 pos = calcPos();
|
||||||
auto batch = pctx->getBatch2D();
|
auto batch = pctx.getBatch2D();
|
||||||
batch->texture(nullptr);
|
batch->texture(nullptr);
|
||||||
batch->setColor(hover ? hoverColor : color);
|
batch->setColor(hover ? hoverColor : color);
|
||||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||||
|
|||||||
@ -21,7 +21,7 @@ namespace gui {
|
|||||||
double value,
|
double value,
|
||||||
double step=1.0,
|
double step=1.0,
|
||||||
int trackWidth=12);
|
int trackWidth=12);
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) override;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) override;
|
||||||
|
|
||||||
virtual void setSupplier(doublesupplier);
|
virtual void setSupplier(doublesupplier);
|
||||||
virtual void setConsumer(doubleconsumer);
|
virtual void setConsumer(doubleconsumer);
|
||||||
|
|||||||
@ -111,11 +111,11 @@ bool UINode::isInside(glm::vec2 point) {
|
|||||||
point.x < pos.x + size.x && point.y < pos.y + size.y);
|
point.x < pos.x + size.x && point.y < pos.y + size.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> UINode::getAt(glm::vec2 point, std::shared_ptr<UINode> self) {
|
std::shared_ptr<UINode> UINode::getAt(const glm::vec2& point, const std::shared_ptr<UINode>& self) {
|
||||||
if (!isInteractive() || !enabled) {
|
if (!isInteractive() || !enabled) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return isInside(point) ? std::move(self) : nullptr;
|
return isInside(point) ? self : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UINode::isInteractive() const {
|
bool UINode::isInteractive() const {
|
||||||
|
|||||||
@ -120,7 +120,7 @@ namespace gui {
|
|||||||
/// @brief Called every frame for all visible elements
|
/// @brief Called every frame for all visible elements
|
||||||
/// @param delta delta timУ
|
/// @param delta delta timУ
|
||||||
virtual void act(float delta) {};
|
virtual void act(float delta) {};
|
||||||
virtual void draw(const DrawContext* pctx, Assets* assets) = 0;
|
virtual void draw(const DrawContext& pctx, const Assets& assets) = 0;
|
||||||
|
|
||||||
virtual void setVisible(bool flag);
|
virtual void setVisible(bool flag);
|
||||||
bool isVisible() const;
|
bool isVisible() const;
|
||||||
@ -190,7 +190,7 @@ namespace gui {
|
|||||||
/// @param pos cursor screen position
|
/// @param pos cursor screen position
|
||||||
/// @param self shared pointer to element
|
/// @param self shared pointer to element
|
||||||
/// @return self, sub-element or nullptr if element is not interractive
|
/// @return self, sub-element or nullptr if element is not interractive
|
||||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self);
|
virtual std::shared_ptr<UINode> getAt(const glm::vec2& pos, const std::shared_ptr<UINode>& self);
|
||||||
|
|
||||||
/// @brief Check if element is opaque for cursor
|
/// @brief Check if element is opaque for cursor
|
||||||
virtual bool isInteractive() const;
|
virtual bool isInteractive() const;
|
||||||
|
|||||||
@ -56,8 +56,8 @@ static runnable create_runnable(
|
|||||||
const xml::xmlelement& element,
|
const xml::xmlelement& element,
|
||||||
const std::string& name
|
const std::string& name
|
||||||
) {
|
) {
|
||||||
if (element->has(name)) {
|
if (element.has(name)) {
|
||||||
std::string text = element->attr(name).getText();
|
std::string text = element.attr(name).getText();
|
||||||
if (!text.empty()) {
|
if (!text.empty()) {
|
||||||
return scripting::create_runnable(
|
return scripting::create_runnable(
|
||||||
reader.getEnvironment(), text, reader.getFilename()
|
reader.getEnvironment(), text, reader.getFilename()
|
||||||
@ -83,78 +83,78 @@ static onaction create_action(
|
|||||||
static void _readUINode(
|
static void _readUINode(
|
||||||
const UiXmlReader& reader, const xml::xmlelement& element, UINode& node
|
const UiXmlReader& reader, const xml::xmlelement& element, UINode& node
|
||||||
) {
|
) {
|
||||||
if (element->has("id")) {
|
if (element.has("id")) {
|
||||||
node.setId(element->attr("id").getText());
|
node.setId(element.attr("id").getText());
|
||||||
}
|
}
|
||||||
if (element->has("pos")) {
|
if (element.has("pos")) {
|
||||||
node.setPos(element->attr("pos").asVec2());
|
node.setPos(element.attr("pos").asVec2());
|
||||||
}
|
}
|
||||||
if (element->has("size")) {
|
if (element.has("size")) {
|
||||||
node.setSize(element->attr("size").asVec2());
|
node.setSize(element.attr("size").asVec2());
|
||||||
}
|
}
|
||||||
if (element->has("color")) {
|
if (element.has("color")) {
|
||||||
glm::vec4 color = element->attr("color").asColor();
|
glm::vec4 color = element.attr("color").asColor();
|
||||||
glm::vec4 hoverColor = color;
|
glm::vec4 hoverColor = color;
|
||||||
glm::vec4 pressedColor = color;
|
glm::vec4 pressedColor = color;
|
||||||
if (element->has("hover-color")) {
|
if (element.has("hover-color")) {
|
||||||
hoverColor = node.getHoverColor();
|
hoverColor = node.getHoverColor();
|
||||||
}
|
}
|
||||||
if (element->has("pressed-color")) {
|
if (element.has("pressed-color")) {
|
||||||
pressedColor = node.getPressedColor();
|
pressedColor = node.getPressedColor();
|
||||||
}
|
}
|
||||||
node.setColor(color);
|
node.setColor(color);
|
||||||
node.setHoverColor(hoverColor);
|
node.setHoverColor(hoverColor);
|
||||||
node.setPressedColor(pressedColor);
|
node.setPressedColor(pressedColor);
|
||||||
}
|
}
|
||||||
if (element->has("margin")) {
|
if (element.has("margin")) {
|
||||||
node.setMargin(element->attr("margin").asVec4());
|
node.setMargin(element.attr("margin").asVec4());
|
||||||
}
|
}
|
||||||
if (element->has("z-index")) {
|
if (element.has("z-index")) {
|
||||||
node.setZIndex(element->attr("z-index").asInt());
|
node.setZIndex(element.attr("z-index").asInt());
|
||||||
}
|
}
|
||||||
if (element->has("interactive")) {
|
if (element.has("interactive")) {
|
||||||
node.setInteractive(element->attr("interactive").asBool());
|
node.setInteractive(element.attr("interactive").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("visible")) {
|
if (element.has("visible")) {
|
||||||
node.setVisible(element->attr("visible").asBool());
|
node.setVisible(element.attr("visible").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("enabled")) {
|
if (element.has("enabled")) {
|
||||||
node.setEnabled(element->attr("enabled").asBool());
|
node.setEnabled(element.attr("enabled").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("position-func")) {
|
if (element.has("position-func")) {
|
||||||
node.setPositionFunc(scripting::create_vec2_supplier(
|
node.setPositionFunc(scripting::create_vec2_supplier(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("position-func").getText(),
|
element.attr("position-func").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (element->has("size-func")) {
|
if (element.has("size-func")) {
|
||||||
node.setSizeFunc(scripting::create_vec2_supplier(
|
node.setSizeFunc(scripting::create_vec2_supplier(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("size-func").getText(),
|
element.attr("size-func").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (element->has("hover-color")) {
|
if (element.has("hover-color")) {
|
||||||
node.setHoverColor(element->attr("hover-color").asColor());
|
node.setHoverColor(element.attr("hover-color").asColor());
|
||||||
}
|
}
|
||||||
if (element->has("pressed-color")) {
|
if (element.has("pressed-color")) {
|
||||||
node.setPressedColor(element->attr("pressed-color").asColor());
|
node.setPressedColor(element.attr("pressed-color").asColor());
|
||||||
}
|
}
|
||||||
std::string alignName = element->attr("align", "").getText();
|
std::string alignName = element.attr("align", "").getText();
|
||||||
node.setAlign(align_from_string(alignName, node.getAlign()));
|
node.setAlign(align_from_string(alignName, node.getAlign()));
|
||||||
|
|
||||||
if (element->has("gravity")) {
|
if (element.has("gravity")) {
|
||||||
node.setGravity(gravity_from_string(
|
node.setGravity(gravity_from_string(
|
||||||
element->attr("gravity").getText()
|
element.attr("gravity").getText()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element->has("tooltip")) {
|
if (element.has("tooltip")) {
|
||||||
node.setTooltip(util::str2wstr_utf8(element->attr("tooltip").getText()));
|
node.setTooltip(util::str2wstr_utf8(element.attr("tooltip").getText()));
|
||||||
}
|
}
|
||||||
if (element->has("tooltip-delay")) {
|
if (element.has("tooltip-delay")) {
|
||||||
node.setTooltipDelay(element->attr("tooltip-delay").asFloat());
|
node.setTooltipDelay(element.attr("tooltip-delay").asFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto onclick = create_action(reader, element, "onclick")) {
|
if (auto onclick = create_action(reader, element, "onclick")) {
|
||||||
@ -169,16 +169,16 @@ static void _readUINode(
|
|||||||
static void _readContainer(UiXmlReader& reader, const xml::xmlelement& element, Container& container) {
|
static void _readContainer(UiXmlReader& reader, const xml::xmlelement& element, Container& container) {
|
||||||
_readUINode(reader, element, container);
|
_readUINode(reader, element, container);
|
||||||
|
|
||||||
if (element->has("scrollable")) {
|
if (element.has("scrollable")) {
|
||||||
container.setScrollable(element->attr("scrollable").asBool());
|
container.setScrollable(element.attr("scrollable").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("scroll-step")) {
|
if (element.has("scroll-step")) {
|
||||||
container.setScrollStep(element->attr("scroll-step").asInt());
|
container.setScrollStep(element.attr("scroll-step").asInt());
|
||||||
}
|
}
|
||||||
for (auto& sub : element->getElements()) {
|
for (auto& sub : element.getElements()) {
|
||||||
if (sub->isText())
|
if (sub->isText())
|
||||||
continue;
|
continue;
|
||||||
auto subnode = reader.readUINode(sub);
|
auto subnode = reader.readUINode(*sub);
|
||||||
if (subnode) {
|
if (subnode) {
|
||||||
container.add(subnode);
|
container.add(subnode);
|
||||||
}
|
}
|
||||||
@ -189,15 +189,17 @@ void UiXmlReader::readUINode(UiXmlReader& reader, const xml::xmlelement& element
|
|||||||
_readContainer(reader, element, container);
|
_readContainer(reader, element, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UiXmlReader::readUINode(UiXmlReader& reader, const xml::xmlelement& element, UINode& node) {
|
void UiXmlReader::readUINode(
|
||||||
|
const UiXmlReader& reader, const xml::xmlelement& element, UINode& node
|
||||||
|
) {
|
||||||
_readUINode(reader, element, node);
|
_readUINode(reader, element, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _readPanel(UiXmlReader& reader, const xml::xmlelement& element, Panel& panel, bool subnodes=true) {
|
static void _readPanel(UiXmlReader& reader, const xml::xmlelement& element, Panel& panel, bool subnodes=true) {
|
||||||
_readUINode(reader, element, panel);
|
_readUINode(reader, element, panel);
|
||||||
|
|
||||||
if (element->has("padding")) {
|
if (element.has("padding")) {
|
||||||
glm::vec4 padding = element->attr("padding").asVec4();
|
glm::vec4 padding = element.attr("padding").asVec4();
|
||||||
panel.setPadding(padding);
|
panel.setPadding(padding);
|
||||||
glm::vec2 size = panel.getSize();
|
glm::vec2 size = panel.getSize();
|
||||||
panel.setSize(glm::vec2(
|
panel.setSize(glm::vec2(
|
||||||
@ -205,23 +207,23 @@ static void _readPanel(UiXmlReader& reader, const xml::xmlelement& element, Pane
|
|||||||
size.y + padding.y + padding.w
|
size.y + padding.y + padding.w
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (element->has("size")) {
|
if (element.has("size")) {
|
||||||
panel.setResizing(false);
|
panel.setResizing(false);
|
||||||
}
|
}
|
||||||
if (element->has("max-length")) {
|
if (element.has("max-length")) {
|
||||||
panel.setMaxLength(element->attr("max-length").asInt());
|
panel.setMaxLength(element.attr("max-length").asInt());
|
||||||
}
|
}
|
||||||
if (element->has("orientation")) {
|
if (element.has("orientation")) {
|
||||||
auto &oname = element->attr("orientation").getText();
|
auto &oname = element.attr("orientation").getText();
|
||||||
if (oname == "horizontal") {
|
if (oname == "horizontal") {
|
||||||
panel.setOrientation(Orientation::horizontal);
|
panel.setOrientation(Orientation::horizontal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (subnodes) {
|
if (subnodes) {
|
||||||
for (auto& sub : element->getElements()) {
|
for (auto& sub : element.getElements()) {
|
||||||
if (sub->isText())
|
if (sub->isText())
|
||||||
continue;
|
continue;
|
||||||
auto subnode = reader.readUINode(sub);
|
auto subnode = reader.readUINode(*sub);
|
||||||
if (subnode) {
|
if (subnode) {
|
||||||
panel.add(subnode);
|
panel.add(subnode);
|
||||||
}
|
}
|
||||||
@ -231,8 +233,8 @@ static void _readPanel(UiXmlReader& reader, const xml::xmlelement& element, Pane
|
|||||||
|
|
||||||
static std::wstring readAndProcessInnerText(const xml::xmlelement& element, const std::string& context) {
|
static std::wstring readAndProcessInnerText(const xml::xmlelement& element, const std::string& context) {
|
||||||
std::wstring text = L"";
|
std::wstring text = L"";
|
||||||
if (element->size() == 1) {
|
if (element.size() == 1) {
|
||||||
std::string source = element->sub(0)->attr("#").getText();
|
std::string source = element.sub(0).attr("#").getText();
|
||||||
util::trim(source);
|
util::trim(source);
|
||||||
text = util::str2wstr_utf8(source);
|
text = util::str2wstr_utf8(source);
|
||||||
if (text[0] == '@') {
|
if (text[0] == '@') {
|
||||||
@ -246,33 +248,38 @@ static std::wstring readAndProcessInnerText(const xml::xmlelement& element, cons
|
|||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readLabel(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readLabel(
|
||||||
|
const UiXmlReader& reader, const xml::xmlelement& element
|
||||||
|
) {
|
||||||
std::wstring text = readAndProcessInnerText(element, reader.getContext());
|
std::wstring text = readAndProcessInnerText(element, reader.getContext());
|
||||||
auto label = std::make_shared<Label>(text);
|
auto label = std::make_shared<Label>(text);
|
||||||
_readUINode(reader, element, *label);
|
_readUINode(reader, element, *label);
|
||||||
if (element->has("valign")) {
|
if (element.has("valign")) {
|
||||||
label->setVerticalAlign(
|
label->setVerticalAlign(
|
||||||
align_from_string(element->attr("valign").getText(), label->getVerticalAlign())
|
align_from_string(element.attr("valign").getText(), label->getVerticalAlign())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (element->has("supplier")) {
|
if (element.has("supplier")) {
|
||||||
label->textSupplier(scripting::create_wstring_supplier(
|
label->textSupplier(scripting::create_wstring_supplier(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("supplier").getText(),
|
element.attr("supplier").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (element->has("autoresize")) {
|
if (element.has("autoresize")) {
|
||||||
label->setAutoResize(element->attr("autoresize").asBool());
|
label->setAutoResize(element.attr("autoresize").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("multiline")) {
|
if (element.has("multiline")) {
|
||||||
label->setMultiline(element->attr("multiline").asBool());
|
label->setMultiline(element.attr("multiline").asBool());
|
||||||
if (!element->has("valign")) {
|
if (!element.has("valign")) {
|
||||||
label->setVerticalAlign(Align::top);
|
label->setVerticalAlign(Align::top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (element->has("text-wrap")) {
|
if (element.has("text-wrap")) {
|
||||||
label->setTextWrapping(element->attr("text-wrap").asBool());
|
label->setTextWrapping(element.attr("text-wrap").asBool());
|
||||||
|
}
|
||||||
|
if (element.has("markup")) {
|
||||||
|
label->setMarkup(element.attr("markup").getText());
|
||||||
}
|
}
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
@ -284,19 +291,19 @@ static std::shared_ptr<UINode> readContainer(UiXmlReader& reader, const xml::xml
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readPanel(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readPanel(UiXmlReader& reader, const xml::xmlelement& element) {
|
||||||
float interval = element->attr("interval", "2").asFloat();
|
float interval = element.attr("interval", "2").asFloat();
|
||||||
auto panel = std::make_shared<Panel>(glm::vec2(), glm::vec4(), interval);
|
auto panel = std::make_shared<Panel>(glm::vec2(), glm::vec4(), interval);
|
||||||
_readPanel(reader, element, *panel);
|
_readPanel(reader, element, *panel);
|
||||||
return panel;
|
return panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readButton(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readButton(UiXmlReader& reader, const xml::xmlelement& element) {
|
||||||
glm::vec4 padding = element->attr("padding", "10").asVec4();
|
glm::vec4 padding = element.attr("padding", "10").asVec4();
|
||||||
|
|
||||||
std::shared_ptr<Button> button;
|
std::shared_ptr<Button> button;
|
||||||
auto& elements = element->getElements();
|
auto& elements = element.getElements();
|
||||||
if (!elements.empty() && elements[0]->getTag() != "#") {
|
if (!elements.empty() && elements[0]->getTag() != "#") {
|
||||||
auto inner = reader.readUINode(element->getElements().at(0));
|
auto inner = reader.readUINode(*elements.at(0));
|
||||||
if (inner != nullptr) {
|
if (inner != nullptr) {
|
||||||
button = std::make_shared<Button>(inner, padding);
|
button = std::make_shared<Button>(inner, padding);
|
||||||
} else {
|
} else {
|
||||||
@ -308,30 +315,32 @@ static std::shared_ptr<UINode> readButton(UiXmlReader& reader, const xml::xmlele
|
|||||||
button = std::make_shared<Button>(text, padding, nullptr);
|
button = std::make_shared<Button>(text, padding, nullptr);
|
||||||
_readPanel(reader, element, *button, true);
|
_readPanel(reader, element, *button, true);
|
||||||
}
|
}
|
||||||
if (element->has("text-align")) {
|
if (element.has("text-align")) {
|
||||||
button->setTextAlign(align_from_string(element->attr("text-align").getText(), button->getTextAlign()));
|
button->setTextAlign(align_from_string(
|
||||||
|
element.attr("text-align").getText(), button->getTextAlign()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, const xml::xmlelement& element) {
|
||||||
auto text = readAndProcessInnerText(element, reader.getContext());
|
auto text = readAndProcessInnerText(element, reader.getContext());
|
||||||
bool checked = element->attr("checked", "false").asBool();
|
bool checked = element.attr("checked", "false").asBool();
|
||||||
auto checkbox = std::make_shared<FullCheckBox>(text, glm::vec2(32), checked);
|
auto checkbox = std::make_shared<FullCheckBox>(text, glm::vec2(32), checked);
|
||||||
_readPanel(reader, element, *checkbox);
|
_readPanel(reader, element, *checkbox);
|
||||||
|
|
||||||
if (element->has("consumer")) {
|
if (element.has("consumer")) {
|
||||||
checkbox->setConsumer(scripting::create_bool_consumer(
|
checkbox->setConsumer(scripting::create_bool_consumer(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("consumer").getText(),
|
element.attr("consumer").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element->has("supplier")) {
|
if (element.has("supplier")) {
|
||||||
checkbox->setSupplier(scripting::create_bool_supplier(
|
checkbox->setSupplier(scripting::create_bool_supplier(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("supplier").getText(),
|
element.attr("supplier").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -339,15 +348,15 @@ static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, const xml::xmle
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlelement& element) {
|
||||||
auto placeholder = util::str2wstr_utf8(element->attr("placeholder", "").getText());
|
auto placeholder = util::str2wstr_utf8(element.attr("placeholder", "").getText());
|
||||||
auto hint = util::str2wstr_utf8(element->attr("hint", "").getText());
|
auto hint = util::str2wstr_utf8(element.attr("hint", "").getText());
|
||||||
auto text = readAndProcessInnerText(element, reader.getContext());
|
auto text = readAndProcessInnerText(element, reader.getContext());
|
||||||
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
|
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
|
||||||
textbox->setHint(hint);
|
textbox->setHint(hint);
|
||||||
|
|
||||||
_readContainer(reader, element, *textbox);
|
_readContainer(reader, element, *textbox);
|
||||||
if (element->has("padding")) {
|
if (element.has("padding")) {
|
||||||
glm::vec4 padding = element->attr("padding").asVec4();
|
glm::vec4 padding = element.attr("padding").asVec4();
|
||||||
textbox->setPadding(padding);
|
textbox->setPadding(padding);
|
||||||
glm::vec2 size = textbox->getSize();
|
glm::vec2 size = textbox->getSize();
|
||||||
textbox->setSize(glm::vec2(
|
textbox->setSize(glm::vec2(
|
||||||
@ -357,55 +366,61 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlel
|
|||||||
}
|
}
|
||||||
textbox->setText(text);
|
textbox->setText(text);
|
||||||
|
|
||||||
if (element->has("multiline")) {
|
if (element.has("syntax")) {
|
||||||
textbox->setMultiline(element->attr("multiline").asBool());
|
textbox->setSyntax(element.attr("syntax").getText());
|
||||||
}
|
}
|
||||||
if (element->has("text-wrap")) {
|
if (element.has("multiline")) {
|
||||||
textbox->setTextWrapping(element->attr("text-wrap").asBool());
|
textbox->setMultiline(element.attr("multiline").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("editable")) {
|
if (element.has("text-wrap")) {
|
||||||
textbox->setEditable(element->attr("editable").asBool());
|
textbox->setTextWrapping(element.attr("text-wrap").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("autoresize")) {
|
if (element.has("editable")) {
|
||||||
textbox->setAutoResize(element->attr("autoresize").asBool());
|
textbox->setEditable(element.attr("editable").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("line-numbers")) {
|
if (element.has("autoresize")) {
|
||||||
textbox->setShowLineNumbers(element->attr("line-numbers").asBool());
|
textbox->setAutoResize(element.attr("autoresize").asBool());
|
||||||
}
|
}
|
||||||
if (element->has("consumer")) {
|
if (element.has("line-numbers")) {
|
||||||
|
textbox->setShowLineNumbers(element.attr("line-numbers").asBool());
|
||||||
|
}
|
||||||
|
if (element.has("markup")) {
|
||||||
|
textbox->setMarkup(element.attr("markup").getText());
|
||||||
|
}
|
||||||
|
if (element.has("consumer")) {
|
||||||
textbox->setTextConsumer(scripting::create_wstring_consumer(
|
textbox->setTextConsumer(scripting::create_wstring_consumer(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("consumer").getText(),
|
element.attr("consumer").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (element->has("sub-consumer")) {
|
if (element.has("sub-consumer")) {
|
||||||
textbox->setTextSubConsumer(scripting::create_wstring_consumer(
|
textbox->setTextSubConsumer(scripting::create_wstring_consumer(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("sub-consumer").getText(),
|
element.attr("sub-consumer").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (element->has("supplier")) {
|
if (element.has("supplier")) {
|
||||||
textbox->setTextSupplier(scripting::create_wstring_supplier(
|
textbox->setTextSupplier(scripting::create_wstring_supplier(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("supplier").getText(),
|
element.attr("supplier").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (element->has("focused-color")) {
|
if (element.has("focused-color")) {
|
||||||
textbox->setFocusedColor(element->attr("focused-color").asColor());
|
textbox->setFocusedColor(element.attr("focused-color").asColor());
|
||||||
}
|
}
|
||||||
if (element->has("error-color")) {
|
if (element.has("error-color")) {
|
||||||
textbox->setErrorColor(element->attr("error-color").asColor());
|
textbox->setErrorColor(element.attr("error-color").asColor());
|
||||||
}
|
}
|
||||||
if (element->has("text-color")) {
|
if (element.has("text-color")) {
|
||||||
textbox->setTextColor(element->attr("text-color").asColor());
|
textbox->setTextColor(element.attr("text-color").asColor());
|
||||||
}
|
}
|
||||||
if (element->has("validator")) {
|
if (element.has("validator")) {
|
||||||
textbox->setTextValidator(scripting::create_wstring_validator(
|
textbox->setTextValidator(scripting::create_wstring_validator(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr("validator").getText(),
|
element.attr("validator").getText(),
|
||||||
reader.getFilename()
|
reader.getFilename()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -418,61 +433,70 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, const xml::xmlel
|
|||||||
return textbox;
|
return textbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readImage(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readImage(
|
||||||
std::string src = element->attr("src", "").getText();
|
const UiXmlReader& reader, const xml::xmlelement& element
|
||||||
|
) {
|
||||||
|
std::string src = element.attr("src", "").getText();
|
||||||
auto image = std::make_shared<Image>(src);
|
auto image = std::make_shared<Image>(src);
|
||||||
_readUINode(reader, element, *image);
|
_readUINode(reader, element, *image);
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readTrackBar(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readTrackBar(
|
||||||
|
const UiXmlReader& reader, const xml::xmlelement& element
|
||||||
|
) {
|
||||||
const auto& env = reader.getEnvironment();
|
const auto& env = reader.getEnvironment();
|
||||||
const auto& file = reader.getFilename();
|
const auto& file = reader.getFilename();
|
||||||
float minv = element->attr("min", "0.0").asFloat();
|
float minv = element.attr("min", "0.0").asFloat();
|
||||||
float maxv = element->attr("max", "1.0").asFloat();
|
float maxv = element.attr("max", "1.0").asFloat();
|
||||||
float def = element->attr("value", "0.0").asFloat();
|
float def = element.attr("value", "0.0").asFloat();
|
||||||
float step = element->attr("step", "1.0").asFloat();
|
float step = element.attr("step", "1.0").asFloat();
|
||||||
int trackWidth = element->attr("track-width", "12").asInt();
|
int trackWidth = element.attr("track-width", "12").asInt();
|
||||||
auto bar = std::make_shared<TrackBar>(minv, maxv, def, step, trackWidth);
|
auto bar = std::make_shared<TrackBar>(minv, maxv, def, step, trackWidth);
|
||||||
_readUINode(reader, element, *bar);
|
_readUINode(reader, element, *bar);
|
||||||
if (element->has("consumer")) {
|
if (element.has("consumer")) {
|
||||||
bar->setConsumer(scripting::create_number_consumer(
|
bar->setConsumer(scripting::create_number_consumer(
|
||||||
env, element->attr("consumer").getText(), file));
|
env, element.attr("consumer").getText(), file));
|
||||||
}
|
}
|
||||||
if (element->has("sub-consumer")) {
|
if (element.has("sub-consumer")) {
|
||||||
bar->setSubConsumer(scripting::create_number_consumer(
|
bar->setSubConsumer(scripting::create_number_consumer(
|
||||||
env, element->attr("sub-consumer").getText(), file));
|
env, element.attr("sub-consumer").getText(), file));
|
||||||
}
|
}
|
||||||
if (element->has("supplier")) {
|
if (element.has("supplier")) {
|
||||||
bar->setSupplier(scripting::create_number_supplier(
|
bar->setSupplier(scripting::create_number_supplier(
|
||||||
env, element->attr("supplier").getText(), file));
|
env, element.attr("supplier").getText(), file));
|
||||||
}
|
}
|
||||||
if (element->has("track-color")) {
|
if (element.has("track-color")) {
|
||||||
bar->setTrackColor(element->attr("track-color").asColor());
|
bar->setTrackColor(element.attr("track-color").asColor());
|
||||||
}
|
}
|
||||||
if (element->has("change-on-release")) {
|
if (element.has("change-on-release")) {
|
||||||
bar->setChangeOnRelease(element->attr("change-on-release").asBool());
|
bar->setChangeOnRelease(element.attr("change-on-release").asBool());
|
||||||
}
|
}
|
||||||
return bar;
|
return bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<UINode> readInputBindBox(UiXmlReader& reader, const xml::xmlelement& element) {
|
static std::shared_ptr<UINode> readInputBindBox(UiXmlReader& reader, const xml::xmlelement& element) {
|
||||||
auto bindname = element->attr("binding").getText();
|
auto bindname = element.attr("binding").getText();
|
||||||
auto found = Events::bindings.find(bindname);
|
auto found = Events::bindings.find(bindname);
|
||||||
if (found == Events::bindings.end()) {
|
if (found == Events::bindings.end()) {
|
||||||
throw std::runtime_error("binding does not exists "+util::quote(bindname));
|
throw std::runtime_error("binding does not exists "+util::quote(bindname));
|
||||||
}
|
}
|
||||||
glm::vec4 padding = element->attr("padding", "6").asVec4();
|
glm::vec4 padding = element.attr("padding", "6").asVec4();
|
||||||
auto bindbox = std::make_shared<InputBindBox>(found->second, padding);
|
auto bindbox = std::make_shared<InputBindBox>(found->second, padding);
|
||||||
_readPanel(reader, element, *bindbox);
|
_readPanel(reader, element, *bindbox);
|
||||||
|
|
||||||
return bindbox;
|
return bindbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
static slotcallback readSlotFunc(InventoryView* view, UiXmlReader& reader, xml::xmlelement& element, const std::string& attr) {
|
static slotcallback readSlotFunc(
|
||||||
|
InventoryView* view,
|
||||||
|
const UiXmlReader& reader,
|
||||||
|
const xml::xmlelement& element,
|
||||||
|
const std::string& attr
|
||||||
|
) {
|
||||||
auto consumer = scripting::create_int_array_consumer(
|
auto consumer = scripting::create_int_array_consumer(
|
||||||
reader.getEnvironment(),
|
reader.getEnvironment(),
|
||||||
element->attr(attr).getText()
|
element.attr(attr).getText()
|
||||||
);
|
);
|
||||||
return [=](uint slot, ItemStack&) {
|
return [=](uint slot, ItemStack&) {
|
||||||
int args[] {int(view->getInventory()->getId()), int(slot)};
|
int args[] {int(view->getInventory()->getId()), int(slot)};
|
||||||
@ -480,22 +504,24 @@ static slotcallback readSlotFunc(InventoryView* view, UiXmlReader& reader, xml::
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readSlot(InventoryView* view, UiXmlReader& reader, xml::xmlelement element) {
|
static void readSlot(
|
||||||
int index = element->attr("index", "0").asInt();
|
InventoryView* view, UiXmlReader& reader, const xml::xmlelement& element
|
||||||
bool itemSource = element->attr("item-source", "false").asBool();
|
) {
|
||||||
bool taking = element->attr("taking", "true").asBool();
|
int index = element.attr("index", "0").asInt();
|
||||||
bool placing = element->attr("placing", "true").asBool();
|
bool itemSource = element.attr("item-source", "false").asBool();
|
||||||
|
bool taking = element.attr("taking", "true").asBool();
|
||||||
|
bool placing = element.attr("placing", "true").asBool();
|
||||||
SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
|
SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
|
||||||
if (element->has("pos")) {
|
if (element.has("pos")) {
|
||||||
layout.position = element->attr("pos").asVec2();
|
layout.position = element.attr("pos").asVec2();
|
||||||
}
|
}
|
||||||
if (element->has("updatefunc")) {
|
if (element.has("updatefunc")) {
|
||||||
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc");
|
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc");
|
||||||
}
|
}
|
||||||
if (element->has("sharefunc")) {
|
if (element.has("sharefunc")) {
|
||||||
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc");
|
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc");
|
||||||
}
|
}
|
||||||
if (element->has("onrightclick")) {
|
if (element.has("onrightclick")) {
|
||||||
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick");
|
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick");
|
||||||
}
|
}
|
||||||
layout.taking = taking;
|
layout.taking = taking;
|
||||||
@ -505,19 +531,21 @@ static void readSlot(InventoryView* view, UiXmlReader& reader, xml::xmlelement e
|
|||||||
view->add(slot);
|
view->add(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readSlotsGrid(InventoryView* view, UiXmlReader& reader, xml::xmlelement element) {
|
static void readSlotsGrid(
|
||||||
int startIndex = element->attr("start-index", "0").asInt();
|
InventoryView* view, const UiXmlReader& reader, const xml::xmlelement& element
|
||||||
int rows = element->attr("rows", "0").asInt();
|
) {
|
||||||
int cols = element->attr("cols", "0").asInt();
|
int startIndex = element.attr("start-index", "0").asInt();
|
||||||
int count = element->attr("count", "0").asInt();
|
int rows = element.attr("rows", "0").asInt();
|
||||||
|
int cols = element.attr("cols", "0").asInt();
|
||||||
|
int count = element.attr("count", "0").asInt();
|
||||||
const int slotSize = InventoryView::SLOT_SIZE;
|
const int slotSize = InventoryView::SLOT_SIZE;
|
||||||
bool taking = element->attr("taking", "true").asBool();
|
bool taking = element.attr("taking", "true").asBool();
|
||||||
bool placing = element->attr("placing", "true").asBool();
|
bool placing = element.attr("placing", "true").asBool();
|
||||||
int interval = element->attr("interval", "-1").asInt();
|
int interval = element.attr("interval", "-1").asInt();
|
||||||
if (interval < 0) {
|
if (interval < 0) {
|
||||||
interval = InventoryView::SLOT_INTERVAL;
|
interval = InventoryView::SLOT_INTERVAL;
|
||||||
}
|
}
|
||||||
int padding = element->attr("padding", "-1").asInt();
|
int padding = element.attr("padding", "-1").asInt();
|
||||||
if (padding < 0) {
|
if (padding < 0) {
|
||||||
padding = interval;
|
padding = interval;
|
||||||
}
|
}
|
||||||
@ -528,18 +556,18 @@ static void readSlotsGrid(InventoryView* view, UiXmlReader& reader, xml::xmlelem
|
|||||||
} else if (count == 0) {
|
} else if (count == 0) {
|
||||||
count = rows * cols;
|
count = rows * cols;
|
||||||
}
|
}
|
||||||
bool itemSource = element->attr("item-source", "false").asBool();
|
bool itemSource = element.attr("item-source", "false").asBool();
|
||||||
SlotLayout layout(-1, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
|
SlotLayout layout(-1, glm::vec2(), true, itemSource, nullptr, nullptr, nullptr);
|
||||||
if (element->has("pos")) {
|
if (element.has("pos")) {
|
||||||
layout.position = element->attr("pos").asVec2();
|
layout.position = element.attr("pos").asVec2();
|
||||||
}
|
}
|
||||||
if (element->has("updatefunc")) {
|
if (element.has("updatefunc")) {
|
||||||
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc");
|
layout.updateFunc = readSlotFunc(view, reader, element, "updatefunc");
|
||||||
}
|
}
|
||||||
if (element->has("sharefunc")) {
|
if (element.has("sharefunc")) {
|
||||||
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc");
|
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc");
|
||||||
}
|
}
|
||||||
if (element->has("onrightclick")) {
|
if (element.has("onrightclick")) {
|
||||||
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick");
|
layout.rightClick = readSlotFunc(view, reader, element, "onrightclick");
|
||||||
}
|
}
|
||||||
layout.padding = padding;
|
layout.padding = padding;
|
||||||
@ -571,11 +599,11 @@ static std::shared_ptr<UINode> readInventory(UiXmlReader& reader, const xml::xml
|
|||||||
reader.addIgnore("slots-grid");
|
reader.addIgnore("slots-grid");
|
||||||
reader.readUINode(reader, element, *view);
|
reader.readUINode(reader, element, *view);
|
||||||
|
|
||||||
for (auto& sub : element->getElements()) {
|
for (auto& sub : element.getElements()) {
|
||||||
if (sub->getTag() == "slot") {
|
if (sub->getTag() == "slot") {
|
||||||
readSlot(view.get(), reader, sub);
|
readSlot(view.get(), reader, *sub);
|
||||||
} else if (sub->getTag() == "slots-grid") {
|
} else if (sub->getTag() == "slots-grid") {
|
||||||
readSlotsGrid(view.get(), reader, sub);
|
readSlotsGrid(view.get(), reader, *sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return view;
|
return view;
|
||||||
@ -618,18 +646,18 @@ void UiXmlReader::addIgnore(const std::string& tag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element) {
|
std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element) {
|
||||||
if (element->has("if")) {
|
if (element.has("if")) {
|
||||||
const auto& cond = element->attr("if").getText();
|
const auto& cond = element.attr("if").getText();
|
||||||
if (cond.empty() || cond == "false" || cond == "nil")
|
if (cond.empty() || cond == "false" || cond == "nil")
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (element->has("ifnot")) {
|
if (element.has("ifnot")) {
|
||||||
const auto& cond = element->attr("ifnot").getText();
|
const auto& cond = element.attr("ifnot").getText();
|
||||||
if (!(cond.empty() || cond == "false" || cond == "nil"))
|
if (!(cond.empty() || cond == "false" || cond == "nil"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& tag = element->getTag();
|
const std::string& tag = element.getTag();
|
||||||
auto found = readers.find(tag);
|
auto found = readers.find(tag);
|
||||||
if (found == readers.end()) {
|
if (found == readers.end()) {
|
||||||
if (ignored.find(tag) != ignored.end()) {
|
if (ignored.find(tag) != ignored.end()) {
|
||||||
@ -638,9 +666,9 @@ std::shared_ptr<UINode> UiXmlReader::readUINode(const xml::xmlelement& element)
|
|||||||
throw std::runtime_error("unsupported element '"+tag+"'");
|
throw std::runtime_error("unsupported element '"+tag+"'");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hascontext = element->has("context");
|
bool hascontext = element.has("context");
|
||||||
if (hascontext) {
|
if (hascontext) {
|
||||||
contextStack.push(element->attr("context").getText());
|
contextStack.push(element.attr("context").getText());
|
||||||
}
|
}
|
||||||
auto node = found->second(*this, element);
|
auto node = found->second(*this, element);
|
||||||
if (hascontext) {
|
if (hascontext) {
|
||||||
@ -655,8 +683,7 @@ std::shared_ptr<UINode> UiXmlReader::readXML(
|
|||||||
) {
|
) {
|
||||||
this->filename = filename;
|
this->filename = filename;
|
||||||
auto document = xml::parse(filename, source);
|
auto document = xml::parse(filename, source);
|
||||||
auto root = document->getRoot();
|
return readUINode(*document->getRoot());
|
||||||
return readUINode(root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<UINode> UiXmlReader::readXML(
|
std::shared_ptr<UINode> UiXmlReader::readXML(
|
||||||
|
|||||||
@ -11,7 +11,8 @@
|
|||||||
namespace gui {
|
namespace gui {
|
||||||
class UiXmlReader;
|
class UiXmlReader;
|
||||||
|
|
||||||
using uinode_reader = std::function<std::shared_ptr<UINode>(UiXmlReader&, xml::xmlelement)>;
|
using uinode_reader = std::function<
|
||||||
|
std::shared_ptr<UINode>(UiXmlReader&, const xml::xmlelement&)>;
|
||||||
|
|
||||||
class UiXmlReader {
|
class UiXmlReader {
|
||||||
std::unordered_map<std::string, uinode_reader> readers;
|
std::unordered_map<std::string, uinode_reader> readers;
|
||||||
@ -29,7 +30,7 @@ namespace gui {
|
|||||||
std::shared_ptr<UINode> readUINode(const xml::xmlelement& element);
|
std::shared_ptr<UINode> readUINode(const xml::xmlelement& element);
|
||||||
|
|
||||||
void readUINode(
|
void readUINode(
|
||||||
UiXmlReader& reader,
|
const UiXmlReader& reader,
|
||||||
const xml::xmlelement& element,
|
const xml::xmlelement& element,
|
||||||
UINode& node
|
UINode& node
|
||||||
);
|
);
|
||||||
|
|||||||
111
src/graphics/ui/markdown.cpp
Normal file
111
src/graphics/ui/markdown.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include "markdown.hpp"
|
||||||
|
|
||||||
|
#include "graphics/core/Font.hpp"
|
||||||
|
|
||||||
|
using namespace markdown;
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
static inline void emit(
|
||||||
|
CharT c, FontStylesScheme& styles, std::basic_stringstream<CharT>& ss
|
||||||
|
) {
|
||||||
|
ss << c;
|
||||||
|
styles.map.emplace_back(styles.palette.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
static inline void emit_md(
|
||||||
|
CharT c, FontStylesScheme& styles, std::basic_stringstream<CharT>& ss
|
||||||
|
) {
|
||||||
|
ss << c;
|
||||||
|
styles.map.emplace_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
static inline void restyle(
|
||||||
|
CharT c,
|
||||||
|
FontStyle& style,
|
||||||
|
FontStylesScheme& styles,
|
||||||
|
std::basic_stringstream<CharT>& ss,
|
||||||
|
int& pos,
|
||||||
|
bool eraseMarkdown
|
||||||
|
) {
|
||||||
|
styles.palette.push_back(style);
|
||||||
|
if (!eraseMarkdown) {
|
||||||
|
emit_md(c, styles, ss);
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
Result<CharT> process_markdown(
|
||||||
|
std::basic_string_view<CharT> source, bool eraseMarkdown
|
||||||
|
) {
|
||||||
|
std::basic_stringstream<CharT> ss;
|
||||||
|
FontStylesScheme styles {
|
||||||
|
// markdown default
|
||||||
|
{{false, false, false, false, glm::vec4(1,1,1,0.5f)}, {}},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
FontStyle style;
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < source.size()) {
|
||||||
|
CharT first = source[pos];
|
||||||
|
if (first == '\\') {
|
||||||
|
if (pos + 1 < source.size()) {
|
||||||
|
CharT second = source[++pos];
|
||||||
|
switch (second) {
|
||||||
|
case '*':
|
||||||
|
case '_':
|
||||||
|
case '~':
|
||||||
|
if (!eraseMarkdown) {
|
||||||
|
emit_md(first, styles, ss);
|
||||||
|
}
|
||||||
|
emit(second, styles, ss);
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
} else if (first == '*') {
|
||||||
|
if (pos + 1 < source.size() && source[pos+1] == '*') {
|
||||||
|
pos++;
|
||||||
|
if (!eraseMarkdown)
|
||||||
|
emit_md(first, styles, ss);
|
||||||
|
style.bold = !style.bold;
|
||||||
|
restyle(first, style, styles, ss, pos, eraseMarkdown);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
style.italic = !style.italic;
|
||||||
|
restyle(first, style, styles, ss, pos, eraseMarkdown);
|
||||||
|
continue;
|
||||||
|
} else if (first == '_' && pos + 1 < source.size() && source[pos+1] == '_') {
|
||||||
|
pos++;
|
||||||
|
if (!eraseMarkdown)
|
||||||
|
emit_md(first, styles, ss);
|
||||||
|
style.underline = !style.underline;
|
||||||
|
restyle(first, style, styles, ss, pos, eraseMarkdown);
|
||||||
|
continue;
|
||||||
|
} else if (first == '~' && pos + 1 < source.size() && source[pos+1] == '~') {
|
||||||
|
pos++;
|
||||||
|
if (!eraseMarkdown)
|
||||||
|
emit_md(first, styles, ss);
|
||||||
|
style.strikethrough = !style.strikethrough;
|
||||||
|
restyle(first, style, styles, ss, pos, eraseMarkdown);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (first == '\n') {
|
||||||
|
styles.palette.push_back(styles.palette.at(1));
|
||||||
|
}
|
||||||
|
emit(first, styles, ss);
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return {ss.str(), std::make_unique<FontStylesScheme>(std::move(styles))};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<char> markdown::process(std::string_view source, bool eraseMarkdown) {
|
||||||
|
return process_markdown(source, eraseMarkdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<wchar_t> markdown::process(std::wstring_view source, bool eraseMarkdown) {
|
||||||
|
return process_markdown(source, eraseMarkdown);
|
||||||
|
}
|
||||||
43
src/graphics/ui/markdown.hpp
Normal file
43
src/graphics/ui/markdown.hpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
struct FontStylesScheme;
|
||||||
|
|
||||||
|
// VoxelCore Markdown dialect
|
||||||
|
|
||||||
|
namespace markdown {
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
struct Result {
|
||||||
|
/// @brief Text with erased markdown
|
||||||
|
std::basic_string<CharT> text;
|
||||||
|
/// @brief Text styles scheme
|
||||||
|
std::unique_ptr<FontStylesScheme> styles;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result<char> process(std::string_view source, bool eraseMarkdown);
|
||||||
|
Result<wchar_t> process(std::wstring_view source, bool eraseMarkdown);
|
||||||
|
|
||||||
|
template <typename CharT>
|
||||||
|
inline std::basic_string<CharT> escape(std::string_view source) {
|
||||||
|
std::basic_stringstream<CharT> ss;
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < source.size()) {
|
||||||
|
CharT first = source[pos];
|
||||||
|
if (first == '\\' && pos + 1 < source.size()) {
|
||||||
|
CharT second = source[++pos];
|
||||||
|
ss << first << second;
|
||||||
|
pos++;
|
||||||
|
continue;
|
||||||
|
} else if (first == '*' || first == '~' || first == '_') {
|
||||||
|
ss << '\\';
|
||||||
|
}
|
||||||
|
ss << first;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,7 +20,9 @@ std::shared_ptr<Inventory> Inventories::create(size_t size) {
|
|||||||
std::shared_ptr<Inventory> Inventories::createVirtual(size_t size) {
|
std::shared_ptr<Inventory> Inventories::createVirtual(size_t size) {
|
||||||
int64_t id;
|
int64_t id;
|
||||||
do {
|
do {
|
||||||
id = -std::max<int64_t>(1LL, std::llabs(random.rand64()));
|
// lua does not support long integers because Number is floating-point
|
||||||
|
// type. Changing int_consumer to use 64 bit integer does not change anything
|
||||||
|
id = -std::max<int64_t>(1LL, std::llabs(random.rand64() % 1000'000'000));
|
||||||
} while (map.find(id) != map.end());
|
} while (map.find(id) != map.end());
|
||||||
|
|
||||||
auto inv = std::make_shared<Inventory>(id, size);
|
auto inv = std::make_shared<Inventory>(id, size);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
Inventory::Inventory(int64_t id, size_t size) : id(id), slots(size) {
|
Inventory::Inventory(int64_t id, size_t size) : id(id), slots(size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Inventory::Inventory(const Inventory& orig) {
|
Inventory::Inventory(const Inventory& orig) : id(0) {
|
||||||
this->slots = orig.slots;
|
this->slots = orig.slots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,9 +31,16 @@ static int l_add_command(lua::State* L) {
|
|||||||
|
|
||||||
static int l_execute(lua::State* L) {
|
static int l_execute(lua::State* L) {
|
||||||
auto prompt = lua::require_string(L, 1);
|
auto prompt = lua::require_string(L, 1);
|
||||||
|
try {
|
||||||
auto result = engine->getCommandsInterpreter()->execute(prompt);
|
auto result = engine->getCommandsInterpreter()->execute(prompt);
|
||||||
lua::pushvalue(L, result);
|
lua::pushvalue(L, result);
|
||||||
return 1;
|
return 1;
|
||||||
|
} catch (const parsing_error& err) {
|
||||||
|
if (std::string(err.what()).find("unknown command ") == 0) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
throw std::runtime_error(err.errorLog());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_set(lua::State* L) {
|
static int l_set(lua::State* L) {
|
||||||
|
|||||||
@ -12,6 +12,8 @@
|
|||||||
#include "graphics/ui/elements/TrackBar.hpp"
|
#include "graphics/ui/elements/TrackBar.hpp"
|
||||||
#include "graphics/ui/elements/UINode.hpp"
|
#include "graphics/ui/elements/UINode.hpp"
|
||||||
#include "graphics/ui/gui_util.hpp"
|
#include "graphics/ui/gui_util.hpp"
|
||||||
|
#include "graphics/ui/markdown.hpp"
|
||||||
|
#include "graphics/core/Font.hpp"
|
||||||
#include "items/Inventories.hpp"
|
#include "items/Inventories.hpp"
|
||||||
#include "util/stringutil.hpp"
|
#include "util/stringutil.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
@ -299,6 +301,22 @@ static int p_get_line_numbers(UINode* node, lua::State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int p_get_syntax(UINode* node, lua::State* L) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
return lua::pushstring(L, box->getSyntax());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int p_get_markup(UINode* node, lua::State* L) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
return lua::pushstring(L, box->getMarkup());
|
||||||
|
} else if (auto label = dynamic_cast<Label*>(node)) {
|
||||||
|
return lua::pushstring(L, label->getMarkup());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int p_get_src(UINode* node, lua::State* L) {
|
static int p_get_src(UINode* node, lua::State* L) {
|
||||||
if (auto image = dynamic_cast<Image*>(node)) {
|
if (auto image = dynamic_cast<Image*>(node)) {
|
||||||
return lua::pushstring(L, image->getTexture());
|
return lua::pushstring(L, image->getTexture());
|
||||||
@ -420,6 +438,8 @@ static int l_gui_getattr(lua::State* L) {
|
|||||||
{"lineNumbers", p_get_line_numbers},
|
{"lineNumbers", p_get_line_numbers},
|
||||||
{"lineAt", p_get_line_at},
|
{"lineAt", p_get_line_at},
|
||||||
{"linePos", p_get_line_pos},
|
{"linePos", p_get_line_pos},
|
||||||
|
{"syntax", p_get_syntax},
|
||||||
|
{"markup", p_get_markup},
|
||||||
{"src", p_get_src},
|
{"src", p_get_src},
|
||||||
{"value", p_get_value},
|
{"value", p_get_value},
|
||||||
{"min", p_get_min},
|
{"min", p_get_min},
|
||||||
@ -512,6 +532,18 @@ static void p_set_line_numbers(UINode* node, lua::State* L, int idx) {
|
|||||||
box->setShowLineNumbers(lua::toboolean(L, idx));
|
box->setShowLineNumbers(lua::toboolean(L, idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void p_set_syntax(UINode* node, lua::State* L, int idx) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
box->setSyntax(lua::require_string(L, idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void p_set_markup(UINode* node, lua::State* L, int idx) {
|
||||||
|
if (auto box = dynamic_cast<TextBox*>(node)) {
|
||||||
|
box->setMarkup(lua::require_string(L, idx));
|
||||||
|
} else if (auto label = dynamic_cast<Label*>(node)) {
|
||||||
|
label->setMarkup(lua::require_string(L, idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
static void p_set_src(UINode* node, lua::State* L, int idx) {
|
static void p_set_src(UINode* node, lua::State* L, int idx) {
|
||||||
if (auto image = dynamic_cast<Image*>(node)) {
|
if (auto image = dynamic_cast<Image*>(node)) {
|
||||||
image->setTexture(lua::require_string(L, idx));
|
image->setTexture(lua::require_string(L, idx));
|
||||||
@ -612,6 +644,8 @@ static int l_gui_setattr(lua::State* L) {
|
|||||||
{"text", p_set_text},
|
{"text", p_set_text},
|
||||||
{"editable", p_set_editable},
|
{"editable", p_set_editable},
|
||||||
{"lineNumbers", p_set_line_numbers},
|
{"lineNumbers", p_set_line_numbers},
|
||||||
|
{"syntax", p_set_syntax},
|
||||||
|
{"markup", p_set_markup},
|
||||||
{"src", p_set_src},
|
{"src", p_set_src},
|
||||||
{"caret", p_set_caret},
|
{"caret", p_set_caret},
|
||||||
{"value", p_set_value},
|
{"value", p_set_value},
|
||||||
@ -694,6 +728,25 @@ static int l_gui_getviewport(lua::State* L) {
|
|||||||
return lua::pushvec2(L, engine->getGUI()->getContainer()->getSize());
|
return lua::pushvec2(L, engine->getGUI()->getContainer()->getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_gui_clear_markup(lua::State* L) {
|
||||||
|
auto lang = lua::require_string(L, 1);
|
||||||
|
std::string text = lua::require_string(L, 2);
|
||||||
|
if (std::strcmp(lang, "md") == 0) {
|
||||||
|
auto [processed, _] = markdown::process(text, true);
|
||||||
|
text = std::move(processed);
|
||||||
|
}
|
||||||
|
return lua::pushstring(L, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_gui_escape_markup(lua::State* L) {
|
||||||
|
auto lang = lua::require_string(L, 1);
|
||||||
|
std::string text = lua::require_string(L, 2);
|
||||||
|
if (std::strcmp(lang, "md") == 0) {
|
||||||
|
text = std::move(markdown::escape<char>(text));
|
||||||
|
}
|
||||||
|
return lua::pushstring(L, text);
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg guilib[] = {
|
const luaL_Reg guilib[] = {
|
||||||
{"get_viewport", lua::wrap<l_gui_getviewport>},
|
{"get_viewport", lua::wrap<l_gui_getviewport>},
|
||||||
{"getattr", lua::wrap<l_gui_getattr>},
|
{"getattr", lua::wrap<l_gui_getattr>},
|
||||||
@ -701,5 +754,8 @@ const luaL_Reg guilib[] = {
|
|||||||
{"get_env", lua::wrap<l_gui_get_env>},
|
{"get_env", lua::wrap<l_gui_get_env>},
|
||||||
{"str", lua::wrap<l_gui_str>},
|
{"str", lua::wrap<l_gui_str>},
|
||||||
{"get_locales_info", lua::wrap<l_gui_get_locales_info>},
|
{"get_locales_info", lua::wrap<l_gui_get_locales_info>},
|
||||||
|
{"clear_markup", lua::wrap<l_gui_clear_markup>},
|
||||||
|
{"escape_markup", lua::wrap<l_gui_escape_markup>},
|
||||||
{"__reindex", lua::wrap<l_gui_reindex>},
|
{"__reindex", lua::wrap<l_gui_reindex>},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|||||||
@ -87,6 +87,9 @@ static int l_send(lua::State* L) {
|
|||||||
connection->send(
|
connection->send(
|
||||||
reinterpret_cast<char*>(bytes->data().data()), bytes->data().size()
|
reinterpret_cast<char*>(bytes->data().data()), bytes->data().size()
|
||||||
);
|
);
|
||||||
|
} else if (lua::isstring(L, 2)) {
|
||||||
|
auto string = lua::tolstring(L, 2);
|
||||||
|
connection->send(string.data(), string.length());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -98,7 +101,8 @@ static int l_recv(lua::State* L) {
|
|||||||
if (connection == nullptr) {
|
if (connection == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
util::Buffer<char> buffer(glm::min(length, connection->available()));
|
length = glm::min(length, connection->available());
|
||||||
|
util::Buffer<char> buffer(length);
|
||||||
|
|
||||||
int size = connection->recv(buffer.data(), length);
|
int size = connection->recv(buffer.data(), length);
|
||||||
if (size == -1) {
|
if (size == -1) {
|
||||||
@ -151,6 +155,16 @@ static int l_is_connected(lua::State* L) {
|
|||||||
return lua::pushboolean(L, false);
|
return lua::pushboolean(L, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_get_address(lua::State* L) {
|
||||||
|
u64id_t id = lua::tointeger(L, 1);
|
||||||
|
if (auto connection = engine->getNetwork().getConnection(id)) {
|
||||||
|
lua::pushstring(L, connection->getAddress());
|
||||||
|
lua::pushinteger(L, connection->getPort());
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int l_is_serveropen(lua::State* L) {
|
static int l_is_serveropen(lua::State* L) {
|
||||||
u64id_t id = lua::tointeger(L, 1);
|
u64id_t id = lua::tointeger(L, 1);
|
||||||
if (auto server = engine->getNetwork().getServer(id)) {
|
if (auto server = engine->getNetwork().getServer(id)) {
|
||||||
@ -159,6 +173,14 @@ static int l_is_serveropen(lua::State* L) {
|
|||||||
return lua::pushboolean(L, false);
|
return lua::pushboolean(L, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_get_serverport(lua::State* L) {
|
||||||
|
u64id_t id = lua::tointeger(L, 1);
|
||||||
|
if (auto server = engine->getNetwork().getServer(id)) {
|
||||||
|
return lua::pushinteger(L, server->getPort());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int l_get_total_upload(lua::State* L) {
|
static int l_get_total_upload(lua::State* L) {
|
||||||
return lua::pushinteger(L, engine->getNetwork().getTotalUpload());
|
return lua::pushinteger(L, engine->getNetwork().getTotalUpload());
|
||||||
}
|
}
|
||||||
@ -180,6 +202,8 @@ const luaL_Reg networklib[] = {
|
|||||||
{"__recv", lua::wrap<l_recv>},
|
{"__recv", lua::wrap<l_recv>},
|
||||||
{"__is_alive", lua::wrap<l_is_alive>},
|
{"__is_alive", lua::wrap<l_is_alive>},
|
||||||
{"__is_connected", lua::wrap<l_is_connected>},
|
{"__is_connected", lua::wrap<l_is_connected>},
|
||||||
|
{"__get_address", lua::wrap<l_get_address>},
|
||||||
{"__is_serveropen", lua::wrap<l_is_serveropen>},
|
{"__is_serveropen", lua::wrap<l_is_serveropen>},
|
||||||
|
{"__get_serverport", lua::wrap<l_get_serverport>},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <stdexcept>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "assets/Assets.hpp"
|
#include "api_lua.hpp"
|
||||||
#include "assets/AssetsLoader.hpp"
|
#include "assets/AssetsLoader.hpp"
|
||||||
|
#include "coders/compression.hpp"
|
||||||
|
#include "coders/gzip.hpp"
|
||||||
#include "coders/json.hpp"
|
#include "coders/json.hpp"
|
||||||
#include "engine.hpp"
|
#include "engine.hpp"
|
||||||
#include "files/files.hpp"
|
|
||||||
#include "files/engine_paths.hpp"
|
#include "files/engine_paths.hpp"
|
||||||
|
#include "files/files.hpp"
|
||||||
|
#include "lighting/Lighting.hpp"
|
||||||
|
#include "voxels/Chunk.hpp"
|
||||||
|
#include "voxels/Chunks.hpp"
|
||||||
#include "world/Level.hpp"
|
#include "world/Level.hpp"
|
||||||
#include "world/World.hpp"
|
#include "world/World.hpp"
|
||||||
#include "api_lua.hpp"
|
|
||||||
|
|
||||||
using namespace scripting;
|
using namespace scripting;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
@ -36,12 +40,12 @@ static int l_get_list(lua::State* L) {
|
|||||||
|
|
||||||
const auto& folder = worlds[i];
|
const auto& folder = worlds[i];
|
||||||
|
|
||||||
auto root = json::parse(files::read_string(folder/fs::u8path("world.json")));
|
auto root =
|
||||||
|
json::parse(files::read_string(folder / fs::u8path("world.json")));
|
||||||
const auto& versionMap = root["version"];
|
const auto& versionMap = root["version"];
|
||||||
int versionMajor = versionMap["major"].asInteger();
|
int versionMajor = versionMap["major"].asInteger();
|
||||||
int versionMinor = versionMap["minor"].asInteger();
|
int versionMinor = versionMap["minor"].asInteger();
|
||||||
|
|
||||||
|
|
||||||
auto name = folder.filename().u8string();
|
auto name = folder.filename().u8string();
|
||||||
lua::pushstring(L, name);
|
lua::pushstring(L, name);
|
||||||
lua::setfield(L, "name");
|
lua::setfield(L, "name");
|
||||||
@ -115,6 +119,118 @@ static int l_get_generator(lua::State* L) {
|
|||||||
return lua::pushstring(L, require_world_info().generator);
|
return lua::pushstring(L, require_world_info().generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_get_chunk_data(lua::State* L) {
|
||||||
|
int x = (int)lua::tointeger(L, 1);
|
||||||
|
int y = (int)lua::tointeger(L, 2);
|
||||||
|
const auto& chunk = level->chunks->getChunk(x, y);
|
||||||
|
if (chunk == nullptr) {
|
||||||
|
lua::pushnil(L);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compress = false;
|
||||||
|
if (lua::gettop(L) >= 3) {
|
||||||
|
compress = lua::toboolean(L, 3);
|
||||||
|
}
|
||||||
|
std::vector<ubyte> chunk_data;
|
||||||
|
if (compress) {
|
||||||
|
size_t rle_compressed_size;
|
||||||
|
size_t gzip_compressed_size;
|
||||||
|
const auto& data_ptr = chunk->encode();
|
||||||
|
ubyte* data = data_ptr.get();
|
||||||
|
const auto& rle_compressed_data_ptr = compression::compress(
|
||||||
|
data,
|
||||||
|
CHUNK_DATA_LEN,
|
||||||
|
rle_compressed_size,
|
||||||
|
compression::Method::EXTRLE16
|
||||||
|
);
|
||||||
|
const auto& gzip_compressed_data = compression::compress(
|
||||||
|
rle_compressed_data_ptr.get(),
|
||||||
|
rle_compressed_size,
|
||||||
|
gzip_compressed_size,
|
||||||
|
compression::Method::GZIP
|
||||||
|
);
|
||||||
|
auto tmp = dataio::h2le(rle_compressed_size);
|
||||||
|
chunk_data.reserve(gzip_compressed_size + sizeof(tmp));
|
||||||
|
chunk_data.insert(
|
||||||
|
chunk_data.begin() + 0, (char*)&tmp, ((char*)&tmp) + sizeof(tmp)
|
||||||
|
);
|
||||||
|
chunk_data.insert(
|
||||||
|
chunk_data.begin() + sizeof(tmp),
|
||||||
|
gzip_compressed_data.get(),
|
||||||
|
gzip_compressed_data.get() + gzip_compressed_size
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const auto& data = chunk->encode();
|
||||||
|
chunk_data.reserve(CHUNK_DATA_LEN);
|
||||||
|
chunk_data.insert(
|
||||||
|
chunk_data.begin(), data.get(), data.get() + CHUNK_DATA_LEN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return lua::newuserdata<lua::LuaBytearray>(L, chunk_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_set_chunk_data(lua::State* L) {
|
||||||
|
int x = (int)lua::tointeger(L, 1);
|
||||||
|
int y = (int)lua::tointeger(L, 2);
|
||||||
|
auto buffer = lua::touserdata<lua::LuaBytearray>(L, 3);
|
||||||
|
bool is_compressed = false;
|
||||||
|
if (lua::gettop(L) >= 4) {
|
||||||
|
is_compressed = lua::toboolean(L, 4);
|
||||||
|
}
|
||||||
|
auto chunk = level->chunks->getChunk(x, y);
|
||||||
|
if(chunk== nullptr){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (is_compressed) {
|
||||||
|
std::vector<ubyte>& raw_data = buffer->data();
|
||||||
|
size_t gzip_decompressed_size =
|
||||||
|
dataio::le2h(*(size_t*)(raw_data.data()));
|
||||||
|
const auto& rle_data = compression::decompress(
|
||||||
|
raw_data.data() + sizeof(gzip_decompressed_size),
|
||||||
|
buffer->data().size() - sizeof(gzip_decompressed_size),
|
||||||
|
gzip_decompressed_size,
|
||||||
|
compression::Method::GZIP
|
||||||
|
);
|
||||||
|
const auto& data = compression::decompress(
|
||||||
|
rle_data.get(),
|
||||||
|
gzip_decompressed_size,
|
||||||
|
CHUNK_DATA_LEN,
|
||||||
|
compression::Method::EXTRLE16
|
||||||
|
);
|
||||||
|
chunk->decode(data.get());
|
||||||
|
} else {
|
||||||
|
chunk->decode(buffer->data().data());
|
||||||
|
}
|
||||||
|
chunk->updateHeights();
|
||||||
|
level->lighting->buildSkyLight(x, y);
|
||||||
|
chunk->flags.modified = true;
|
||||||
|
level->lighting->onChunkLoaded(x, y, true);
|
||||||
|
|
||||||
|
chunk = level->chunks->getChunk(x - 1, y);
|
||||||
|
if (chunk != nullptr) {
|
||||||
|
chunk->flags.modified = true;
|
||||||
|
level->lighting->onChunkLoaded(x - 1, y, true);
|
||||||
|
}
|
||||||
|
chunk = level->chunks->getChunk(x + 1, y);
|
||||||
|
if (chunk != nullptr) {
|
||||||
|
chunk->flags.modified = true;
|
||||||
|
level->lighting->onChunkLoaded(x + 1, y, true);
|
||||||
|
}
|
||||||
|
chunk = level->chunks->getChunk(x, y - 1);
|
||||||
|
if (chunk != nullptr) {
|
||||||
|
chunk->flags.modified = true;
|
||||||
|
level->lighting->onChunkLoaded(x, y - 1, true);
|
||||||
|
}
|
||||||
|
chunk = level->chunks->getChunk(x, y + 1);
|
||||||
|
if (chunk != nullptr) {
|
||||||
|
chunk->flags.modified = true;
|
||||||
|
level->lighting->onChunkLoaded(x, y + 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg worldlib[] = {
|
const luaL_Reg worldlib[] = {
|
||||||
{"is_open", lua::wrap<l_is_open>},
|
{"is_open", lua::wrap<l_is_open>},
|
||||||
{"get_list", lua::wrap<l_get_list>},
|
{"get_list", lua::wrap<l_get_list>},
|
||||||
@ -128,4 +244,7 @@ const luaL_Reg worldlib[] = {
|
|||||||
{"is_day", lua::wrap<l_is_day>},
|
{"is_day", lua::wrap<l_is_day>},
|
||||||
{"is_night", lua::wrap<l_is_night>},
|
{"is_night", lua::wrap<l_is_night>},
|
||||||
{"exists", lua::wrap<l_exists>},
|
{"exists", lua::wrap<l_exists>},
|
||||||
{NULL, NULL}};
|
{"get_chunk_data", lua::wrap<l_get_chunk_data>},
|
||||||
|
{"set_chunk_data", lua::wrap<l_set_chunk_data>},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|||||||
@ -191,7 +191,7 @@ void scripting::on_content_load(Content* content) {
|
|||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
}
|
}
|
||||||
if (lua::getglobal(L, "item")) {
|
if (lua::getglobal(L, "item")) {
|
||||||
push_properties_tables(L, indices.blocks);
|
push_properties_tables(L, indices.items);
|
||||||
lua::setfield(L, "properties");
|
lua::setfield(L, "properties");
|
||||||
lua::pop(L);
|
lua::pop(L);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -244,10 +244,11 @@ static inline int sendsocket(
|
|||||||
return send(descriptor, buf, len, flags);
|
return send(descriptor, buf, len, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string to_string(const sockaddr_in* addr) {
|
static std::string to_string(const sockaddr_in& addr, bool port=true) {
|
||||||
char ip[INET_ADDRSTRLEN];
|
char ip[INET_ADDRSTRLEN];
|
||||||
if (inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN)) {
|
if (inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN)) {
|
||||||
return std::string(ip)+":"+std::to_string(htons(addr->sin_port));
|
return std::string(ip) +
|
||||||
|
(port ? (":" + std::to_string(htons(addr.sin_port))) : "");
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -266,7 +267,7 @@ class SocketConnection : public Connection {
|
|||||||
|
|
||||||
void connectSocket() {
|
void connectSocket() {
|
||||||
state = ConnectionState::CONNECTING;
|
state = ConnectionState::CONNECTING;
|
||||||
logger.info() << "connecting to " << to_string(&addr);
|
logger.info() << "connecting to " << to_string(addr);
|
||||||
int res = connectsocket(descriptor, (const sockaddr*)&addr, sizeof(sockaddr_in));
|
int res = connectsocket(descriptor, (const sockaddr*)&addr, sizeof(sockaddr_in));
|
||||||
if (res < 0) {
|
if (res < 0) {
|
||||||
auto error = handle_socket_error("Connect failed");
|
auto error = handle_socket_error("Connect failed");
|
||||||
@ -275,7 +276,7 @@ class SocketConnection : public Connection {
|
|||||||
logger.error() << error.what();
|
logger.error() << error.what();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info() << "connected to " << to_string(&addr);
|
logger.info() << "connected to " << to_string(addr);
|
||||||
state = ConnectionState::CONNECTED;
|
state = ConnectionState::CONNECTED;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
@ -292,22 +293,17 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void connect(runnable callback) override {
|
void startListen() {
|
||||||
thread = std::make_unique<std::thread>([this, callback]() {
|
|
||||||
connectSocket();
|
|
||||||
if (state == ConnectionState::CONNECTED) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
while (state == ConnectionState::CONNECTED) {
|
while (state == ConnectionState::CONNECTED) {
|
||||||
int size = recvsocket(descriptor, buffer.data(), buffer.size());
|
int size = recvsocket(descriptor, buffer.data(), buffer.size());
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
logger.info() << "closed connection with " << to_string(&addr);
|
logger.info() << "closed connection with " << to_string(addr);
|
||||||
closesocket(descriptor);
|
closesocket(descriptor);
|
||||||
state = ConnectionState::CLOSED;
|
state = ConnectionState::CLOSED;
|
||||||
break;
|
break;
|
||||||
} else if (size < 0) {
|
} else if (size < 0) {
|
||||||
logger.info() << "an error ocurred while receiving from "
|
logger.warning() << "an error ocurred while receiving from "
|
||||||
<< to_string(&addr);
|
<< to_string(addr);
|
||||||
auto error = handle_socket_error("recv(...) error");
|
auto error = handle_socket_error("recv(...) error");
|
||||||
closesocket(descriptor);
|
closesocket(descriptor);
|
||||||
state = ConnectionState::CLOSED;
|
state = ConnectionState::CLOSED;
|
||||||
@ -321,8 +317,22 @@ public:
|
|||||||
}
|
}
|
||||||
totalDownload += size;
|
totalDownload += size;
|
||||||
}
|
}
|
||||||
logger.info() << "read " << size << " bytes from " << to_string(&addr);
|
logger.debug() << "read " << size << " bytes from " << to_string(addr);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void startClient() {
|
||||||
|
state = ConnectionState::CONNECTED;
|
||||||
|
thread = std::make_unique<std::thread>([this]() { startListen();});
|
||||||
|
}
|
||||||
|
|
||||||
|
void connect(runnable callback) override {
|
||||||
|
thread = std::make_unique<std::thread>([this, callback]() {
|
||||||
|
connectSocket();
|
||||||
|
if (state == ConnectionState::CONNECTED) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
startListen();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,6 +390,14 @@ public:
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getPort() const override {
|
||||||
|
return htons(addr.sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getAddress() const override {
|
||||||
|
return to_string(addr, false);
|
||||||
|
}
|
||||||
|
|
||||||
static std::shared_ptr<SocketConnection> connect(
|
static std::shared_ptr<SocketConnection> connect(
|
||||||
const std::string& address, int port, runnable callback
|
const std::string& address, int port, runnable callback
|
||||||
) {
|
) {
|
||||||
@ -421,9 +439,10 @@ class SocketTcpSServer : public TcpServer {
|
|||||||
std::mutex clientsMutex;
|
std::mutex clientsMutex;
|
||||||
bool open = true;
|
bool open = true;
|
||||||
std::unique_ptr<std::thread> thread = nullptr;
|
std::unique_ptr<std::thread> thread = nullptr;
|
||||||
|
int port;
|
||||||
public:
|
public:
|
||||||
SocketTcpSServer(Network* network, SOCKET descriptor)
|
SocketTcpSServer(Network* network, SOCKET descriptor, int port)
|
||||||
: network(network), descriptor(descriptor) {}
|
: network(network), descriptor(descriptor), port(port) {}
|
||||||
|
|
||||||
~SocketTcpSServer() {
|
~SocketTcpSServer() {
|
||||||
closeSocket();
|
closeSocket();
|
||||||
@ -445,10 +464,11 @@ public:
|
|||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
logger.info() << "client connected: " << to_string(&address);
|
logger.info() << "client connected: " << to_string(address);
|
||||||
auto socket = std::make_shared<SocketConnection>(
|
auto socket = std::make_shared<SocketConnection>(
|
||||||
clientDescriptor, address
|
clientDescriptor, address
|
||||||
);
|
);
|
||||||
|
socket->startClient();
|
||||||
u64id_t id = network->addConnection(socket);
|
u64id_t id = network->addConnection(socket);
|
||||||
{
|
{
|
||||||
std::lock_guard lock(clientsMutex);
|
std::lock_guard lock(clientsMutex);
|
||||||
@ -488,6 +508,11 @@ public:
|
|||||||
bool isOpen() override {
|
bool isOpen() override {
|
||||||
return open;
|
return open;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getPort() const override {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
static std::shared_ptr<SocketTcpSServer> openServer(
|
static std::shared_ptr<SocketTcpSServer> openServer(
|
||||||
Network* network, int port, consumer<u64id_t> handler
|
Network* network, int port, consumer<u64id_t> handler
|
||||||
) {
|
) {
|
||||||
@ -515,7 +540,8 @@ public:
|
|||||||
throw std::runtime_error("could not bind port "+std::to_string(port));
|
throw std::runtime_error("could not bind port "+std::to_string(port));
|
||||||
}
|
}
|
||||||
logger.info() << "opened server at port " << port;
|
logger.info() << "opened server at port " << port;
|
||||||
auto server = std::make_shared<SocketTcpSServer>(network, descriptor);
|
auto server =
|
||||||
|
std::make_shared<SocketTcpSServer>(network, descriptor, port);
|
||||||
server->startListen(std::move(handler));
|
server->startListen(std::move(handler));
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,9 @@ namespace network {
|
|||||||
virtual size_t pullUpload() = 0;
|
virtual size_t pullUpload() = 0;
|
||||||
virtual size_t pullDownload() = 0;
|
virtual size_t pullDownload() = 0;
|
||||||
|
|
||||||
|
virtual int getPort() const = 0;
|
||||||
|
virtual std::string getAddress() const = 0;
|
||||||
|
|
||||||
virtual ConnectionState getState() const = 0;
|
virtual ConnectionState getState() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ namespace network {
|
|||||||
virtual void startListen(consumer<u64id_t> handler) = 0;
|
virtual void startListen(consumer<u64id_t> handler) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
virtual bool isOpen() = 0;
|
virtual bool isOpen() = 0;
|
||||||
|
virtual int getPort() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Network {
|
class Network {
|
||||||
|
|||||||
@ -53,7 +53,7 @@ struct ParticlesPreset : public Serializable {
|
|||||||
/// @brief Size of random sub-uv region
|
/// @brief Size of random sub-uv region
|
||||||
float randomSubUV = 1.0f;
|
float randomSubUV = 1.0f;
|
||||||
/// @brief Animation frames
|
/// @brief Animation frames
|
||||||
std::vector<std::string> frames {};
|
std::vector<std::string> frames;
|
||||||
|
|
||||||
dv::value serialize() const override;
|
dv::value serialize() const override;
|
||||||
void deserialize(const dv::value& src) override;
|
void deserialize(const dv::value& src) override;
|
||||||
|
|||||||
@ -180,7 +180,7 @@ namespace util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TCoord getHeight() const {
|
TCoord getHeight() const {
|
||||||
return sizeX;
|
return sizeY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<T>& getBuffer() const {
|
const std::vector<T>& getBuffer() const {
|
||||||
|
|||||||
@ -349,7 +349,7 @@ std::string util::mangleid(uint64_t value) {
|
|||||||
util::Buffer<ubyte> util::base64_decode(const char* str, size_t size) {
|
util::Buffer<ubyte> util::base64_decode(const char* str, size_t size) {
|
||||||
util::Buffer<ubyte> bytes((size / 4) * 3);
|
util::Buffer<ubyte> bytes((size / 4) * 3);
|
||||||
ubyte* dst = bytes.data();
|
ubyte* dst = bytes.data();
|
||||||
for (size_t i = 0; i < size;) {
|
for (size_t i = 0; i < (size / 4) * 4;) {
|
||||||
ubyte a = base64_decode_char(ubyte(str[i++]));
|
ubyte a = base64_decode_char(ubyte(str[i++]));
|
||||||
ubyte b = base64_decode_char(ubyte(str[i++]));
|
ubyte b = base64_decode_char(ubyte(str[i++]));
|
||||||
ubyte c = base64_decode_char(ubyte(str[i++]));
|
ubyte c = base64_decode_char(ubyte(str[i++]));
|
||||||
|
|||||||
@ -422,7 +422,7 @@ void Chunks::set(
|
|||||||
if (lz == 0 && (chunk = getChunk(cx, cz - 1))) {
|
if (lz == 0 && (chunk = getChunk(cx, cz - 1))) {
|
||||||
chunk->flags.modified = true;
|
chunk->flags.modified = true;
|
||||||
}
|
}
|
||||||
if (lx == CHUNK_W - 1 && (chunk = getChunk(cx, cz))) {
|
if (lx == CHUNK_W - 1 && (chunk = getChunk(cx + 1, cz))) {
|
||||||
chunk->flags.modified = true;
|
chunk->flags.modified = true;
|
||||||
}
|
}
|
||||||
if (lz == CHUNK_D - 1 && (chunk = getChunk(cx, cz + 1))) {
|
if (lz == CHUNK_D - 1 && (chunk = getChunk(cx, cz + 1))) {
|
||||||
|
|||||||
20
test/coders/lua_parsing.cpp
Normal file
20
test/coders/lua_parsing.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "coders/commons.hpp"
|
||||||
|
#include "coders/lua_parsing.hpp"
|
||||||
|
#include "files/files.hpp"
|
||||||
|
#include "util/stringutil.hpp"
|
||||||
|
|
||||||
|
TEST(lua_parsing, Tokenizer) {
|
||||||
|
auto filename = "../../res/scripts/stdlib.lua";
|
||||||
|
auto source = files::read_string(std::filesystem::u8path(filename));
|
||||||
|
try {
|
||||||
|
auto tokens = lua::tokenize(filename, source);
|
||||||
|
for (const auto& token : tokens) {
|
||||||
|
std::cout << (int)token.tag << " " << util::quote(token.text) << std::endl;
|
||||||
|
}
|
||||||
|
} catch (const parsing_error& err) {
|
||||||
|
std::cerr << err.errorLog() << std::endl;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user