Merge branch 'main' of https://github.com/MihailRis/VoxelEngine-Cpp
This commit is contained in:
commit
bb96db8d55
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
||||
run: ./dev/fix_dylibs.sh VoxelEngine Release build
|
||||
|
||||
- name: Run tests
|
||||
run: ctest --test-dir build
|
||||
run: ctest --output-on-failure --test-dir build
|
||||
|
||||
- name: Create DMG
|
||||
run: |
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -48,3 +48,7 @@ appimage-build/
|
||||
/res/content/*
|
||||
!/res/content/base
|
||||
*.mtl
|
||||
|
||||
# libs
|
||||
/libs/
|
||||
/vcpkg_installed/
|
||||
@ -70,6 +70,10 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -lstdc++fs")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} VoxelEngineSrc winmm)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} VoxelEngineSrc ${CMAKE_DL_LIBS})
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/res DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
@ -12,6 +12,12 @@ Icon type defines a source of an item image displayed in inventory.
|
||||
- **items** (generated from *png* files in *res/textures/items/*)
|
||||
- **block** - block preview. Block ID must be specified in **icon** property. Example: *base:wood*.
|
||||
|
||||
### Item model - `model-name`
|
||||
|
||||
Name of the item model. The model will be loaded automatically.
|
||||
Default value is `packid:itemname.model`.
|
||||
If the model is not specified, an automatic one will be generated.
|
||||
|
||||
## Behaviour
|
||||
|
||||
### *placing-block*
|
||||
|
||||
@ -21,6 +21,7 @@ Subsections:
|
||||
- [player](scripting/builtins/libplayer.md)
|
||||
- [quat](scripting/builtins/libquat.md)
|
||||
- [time](scripting/builtins/libtime.md)
|
||||
- [utf8](scripting/builtins/libutf8.md)
|
||||
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
|
||||
- [world](scripting/builtins/libworld.md)
|
||||
- [Module core:bit_converter](scripting/modules/core_bit_converter.md)
|
||||
|
||||
@ -23,6 +23,9 @@ entities.exists(uid: int) -> bool
|
||||
-- Returns entity definition index by UID
|
||||
entities.get_def(uid: int) -> int
|
||||
|
||||
-- Returns entity 'hitbox' property value
|
||||
entities.def_hitbox(id: int) -> vec3
|
||||
|
||||
-- Returns entity definition name by index (string ID).
|
||||
entities.def_name(id: int) -> str
|
||||
|
||||
|
||||
@ -18,4 +18,13 @@ item.defs_count() -> int
|
||||
|
||||
-- Returns item icon name to use in 'src' property of an image element
|
||||
item.icon(itemid: int) -> str
|
||||
|
||||
-- Returns the integer id 'placing-block' or 0
|
||||
item.placing_block(itemid: int) -> int
|
||||
|
||||
-- Returns the value of the `model-name` property
|
||||
item.model_name(itemid: int) -> str
|
||||
|
||||
-- Returns item emission property value
|
||||
item.emission(itemid: int) -> str
|
||||
```
|
||||
|
||||
27
doc/en/scripting/builtins/libutf8.md
Normal file
27
doc/en/scripting/builtins/libutf8.md
Normal file
@ -0,0 +1,27 @@
|
||||
# *utf8* library
|
||||
|
||||
The library provides functions for working with UTF-8.
|
||||
|
||||
```lua
|
||||
-- Converts a UTF-8 string to a Bytearray or an array of numbers if
|
||||
-- the second argument is true
|
||||
utf8.tobytes(text: str, [optional] usetable=false) -> Bytearray|table
|
||||
|
||||
-- Converts a Bytearray or an array of numbers to a UTF-8 string
|
||||
utf8.tostring(bytes: Bytearray|table) -> str
|
||||
|
||||
-- Returns the length of a Unicode string
|
||||
utf8.length(text: str) -> int
|
||||
|
||||
-- Returns the code of the first character of the string
|
||||
utf8.codepoint(chars: str) -> int
|
||||
|
||||
-- Returns a substring from position startchar to endchar inclusive
|
||||
utf8.sub(text: str, startchar: int, [optional] endchar: int) -> str
|
||||
|
||||
-- Converts a string to uppercase
|
||||
utf8.upper(text: str) -> str
|
||||
|
||||
-- Converts a string to lowercase
|
||||
utf8.lower(text: str) -> str
|
||||
```
|
||||
@ -1,6 +1,7 @@
|
||||
# *world* library
|
||||
|
||||
```lua
|
||||
-- Returns worlds information.
|
||||
world.get_list() -> tables array {
|
||||
-- world name
|
||||
name: str,
|
||||
@ -27,6 +28,9 @@ world.get_total_time() -> number
|
||||
-- Returns world seed.
|
||||
world.get_seed() -> int
|
||||
|
||||
-- Returns generator name.
|
||||
world.get_generator() -> str
|
||||
|
||||
-- Proves that this is the current time during the day
|
||||
-- from 0.333(8 am) to 0.833(8 pm).
|
||||
world.is_day() -> boolean
|
||||
|
||||
@ -136,3 +136,30 @@ function on_hud_close(playerid: int)
|
||||
```
|
||||
|
||||
Called on world close (before saving)
|
||||
|
||||
## *events* library
|
||||
|
||||
```lua
|
||||
events.on(code: str, handler: function)
|
||||
```
|
||||
|
||||
Adds an event handler by its code, not limited to the standard ones.
|
||||
|
||||
```lua
|
||||
events.reset(code: str, [optional] handler: function)
|
||||
```
|
||||
|
||||
Removes the event, adding a handler if specified.
|
||||
|
||||
```lua
|
||||
events.emit(code: str, args...) -> bool
|
||||
```
|
||||
|
||||
Emits an event by code. If the event does not exist, nothing will happen.
|
||||
The existence of an event is determined by the presence of handlers.
|
||||
|
||||
```lua
|
||||
events.remove_by_prefix(packid: str)
|
||||
```
|
||||
|
||||
Removes all events with the prefix `packid:`. When you exit the world, events from all packs are unloaded, including `core:`.
|
||||
|
||||
@ -66,6 +66,18 @@ input.get_binding_text(bindname: str) -> str
|
||||
|
||||
Returns text representation of button by binding name.
|
||||
|
||||
```python
|
||||
input.is_active(bindname: str) -> bool
|
||||
```
|
||||
|
||||
Checks if the binding is active.
|
||||
|
||||
```python
|
||||
input.set_enabled(bindname: str, flag: bool)
|
||||
```
|
||||
|
||||
Enables/disables binding until leaving the world.
|
||||
|
||||
```python
|
||||
input.is_pressed(code: str) -> bool
|
||||
```
|
||||
|
||||
@ -72,15 +72,13 @@ Fragments used by the generator must present in the directory:
|
||||
|
||||
## Structures
|
||||
|
||||
A structure is a set of rules for inserting a fragment into the world by the generator. It currently has no properties, being created as empty objects in the `generators/generator_name.files/structures.json` file. Example:
|
||||
```lua
|
||||
{
|
||||
"tree0": {},
|
||||
"tree1": {},
|
||||
"tree2": {},
|
||||
"tower": {},
|
||||
"coal_ore0": {}
|
||||
}
|
||||
A structure is a set of rules for inserting a fragment into the world by the generator. It currently has no properties, being created as empty objects in the `generators/generator_name.files/structures.toml` file. Example:
|
||||
```toml
|
||||
tree0 = {}
|
||||
tree1 = {}
|
||||
tree2 = {}
|
||||
tower = {}
|
||||
coal_ore0 = {}
|
||||
```
|
||||
|
||||
Currently, the name of the structure must match the name of the fragment used.
|
||||
@ -136,7 +134,7 @@ structures = [
|
||||
- block - plant block
|
||||
- structure-chance - probability of generating a small structure on a surface block.
|
||||
- structures - structures randomly placed on the surface.
|
||||
- name - name of the structure declared in `structures.json`.
|
||||
- name - name of the structure declared in `structures.toml`.
|
||||
- weight - weight directly affecting the chance of choosing a specific structure.
|
||||
|
||||
### Biome Parameters
|
||||
@ -301,6 +299,7 @@ Changes the heightmap size.
|
||||
Available interpolation modes:
|
||||
- 'nearest' - no interpolation
|
||||
- 'linear' - bilinear interpolation
|
||||
- 'cubic' - bicubic interpolation
|
||||
|
||||
### heightmap:crop(...)
|
||||
|
||||
@ -352,7 +351,15 @@ generation.save_fragment(
|
||||
|
||||
The fragment size is available as the `size` property.
|
||||
|
||||
A fragment can be cropped to fit its contents (air is ignored) by calling the `fragment:crop()` method.
|
||||
### Methods
|
||||
|
||||
```lua
|
||||
-- Crop a fragment to content
|
||||
fragment:crop()
|
||||
|
||||
-- Set a fragment to the world at the specified position
|
||||
fragment:place(position: vec3, [optional] rotation:int=0)
|
||||
```
|
||||
|
||||
## Generating a height map
|
||||
|
||||
|
||||
@ -99,6 +99,7 @@ Inner text - initially entered text
|
||||
- `placeholder` - placeholder text (used if the text field is empty)
|
||||
- `supplier` - text supplier (called every frame)
|
||||
- `consumer` - lua function that receives the entered text. Called only when input is complete
|
||||
- `sub-consumer` - lua function-receiver of the input text. Called during text input or deletion.
|
||||
- `autoresize` - automatic change of element size (default - false). Does not affect font size.
|
||||
- `multiline` - allows display of multiline text.
|
||||
- `text-wrap` - allows automatic text wrapping (works only with multiline: "true")
|
||||
|
||||
@ -99,4 +99,4 @@
|
||||
| save-skeleton-pose | поза скелета сущности | false |
|
||||
| save-skeleton-textures | динамически назначенные текстуры | false |
|
||||
| save-body-velocity | скорость движения тела | true |
|
||||
| save-body-settings | измененные настройки тела <br>(type, damping, crouching) | false |
|
||||
| save-body-settings | измененные настройки тела <br>(type, damping, crouching) | true |
|
||||
|
||||
@ -11,6 +11,12 @@
|
||||
- items (генерируется из png файлов в `res/textures/items/`)
|
||||
- `block` - отображает предпросмотр блока. В icon указывается строковый id блока который нужно отображать. Пример `base:wood`
|
||||
|
||||
### Модель предмета - `model-name`
|
||||
|
||||
Имя модели предмета. Модель будет загружена автоматически.
|
||||
Значение по-умолчанию - `packid:itemname.model`.
|
||||
Если модель не указана, будет сгенерирована автоматическию
|
||||
|
||||
## Поведение
|
||||
|
||||
### Устанавливаемый блок - `placing-block`
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
- [player](scripting/builtins/libplayer.md)
|
||||
- [quat](scripting/builtins/libquat.md)
|
||||
- [time](scripting/builtins/libtime.md)
|
||||
- [utf8](scripting/builtins/libutf8.md)
|
||||
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
|
||||
- [world](scripting/builtins/libworld.md)
|
||||
- [Модуль core:bit_converter](scripting/modules/core_bit_converter.md)
|
||||
|
||||
@ -26,6 +26,9 @@ entities.get_def(uid: int) -> int
|
||||
-- Возвращает имя определения сущности по индексу (строковый ID).
|
||||
entities.def_name(id: int) -> str
|
||||
|
||||
-- Возвращает значение свойства 'hitbox' сущности
|
||||
entities.def_hitbox(id: int) -> vec3
|
||||
|
||||
-- Возвращает индекс определения сущности по имени (числовой ID).
|
||||
entities.def_index(name: str) -> int
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ item.name(itemid: int) -> str
|
||||
item.index(name: str) -> int
|
||||
|
||||
-- Возвращает название предмета, отображаемое в интерфейсе.
|
||||
item.caption(blockid: int) -> str
|
||||
item.caption(itemid: int) -> str
|
||||
|
||||
-- Возвращает максимальный размер стопки для предмета.
|
||||
item.stack_size(itemid: int) -> int
|
||||
@ -18,6 +18,15 @@ item.defs_count() -> int
|
||||
|
||||
-- Возвращает имя иконки предмета для использования в свойстве 'src' элемента image
|
||||
item.icon(itemid: int) -> str
|
||||
|
||||
-- Возвращает числовой id блока, назначенного как 'placing-block' или 0
|
||||
item.placing_block(itemid: int) -> int
|
||||
|
||||
-- Возвращает значение свойства `model-name`
|
||||
item.model_name(itemid: int) -> str
|
||||
|
||||
-- Возвращает emission параметр у предмета
|
||||
item.emission(itemid: int) -> str
|
||||
```
|
||||
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@ file.write(pack.shared_file(PACK_ID, "example.txt"), text)
|
||||
```
|
||||
Для пака *containermod* запишет текст в файл `config:containermod/example.txt`
|
||||
|
||||
Используйте для хранения данныхm общих для всех миров.
|
||||
Используйте для хранения данных общих для всех миров.
|
||||
|
||||
```python
|
||||
pack.get_folder(packid: str) -> str
|
||||
|
||||
27
doc/ru/scripting/builtins/libutf8.md
Normal file
27
doc/ru/scripting/builtins/libutf8.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Библиотека *utf8*
|
||||
|
||||
Библиотека предоставляет функции для работы с UTF-8.
|
||||
|
||||
```lua
|
||||
-- Конвертирует UTF-8 строку в Bytearray или массив чисел если
|
||||
-- второй аргумент - true
|
||||
utf8.tobytes(text: str, [опционально] usetable=false) -> Bytearray|table
|
||||
|
||||
-- Конвертирует Bytearray или массив чисел в UTF-8 строку
|
||||
utf8.tostring(bytes: Bytearray|table) -> str
|
||||
|
||||
-- Возвращает длину юникод-строки
|
||||
utf8.length(text: str) -> int
|
||||
|
||||
-- Возвращает код первого символа строки
|
||||
utf8.codepoint(chars: str) -> int
|
||||
|
||||
-- Возвращает подстроку от позиции startchar до endchar включительно
|
||||
utf8.sub(text: str, startchar: int, [опционально] endchar: int) -> str
|
||||
|
||||
-- Переводит строку в вверхний регистр
|
||||
utf8.upper(text: str) -> str
|
||||
|
||||
-- Переводит строку в нижний регистр
|
||||
utf8.lower(text: str) -> str
|
||||
```
|
||||
@ -27,6 +27,9 @@ world.get_total_time() -> number
|
||||
-- Возвращает зерно мира.
|
||||
world.get_seed() -> int
|
||||
|
||||
-- Возвращает имя генератора.
|
||||
world.get_generator() -> str
|
||||
|
||||
-- Проверяет существование мира по имени.
|
||||
world.exists() -> bool
|
||||
|
||||
|
||||
@ -135,3 +135,30 @@ function on_hud_close(playerid: int)
|
||||
```
|
||||
|
||||
Вызывается при выходе из мира, перед его сохранением.
|
||||
|
||||
## Библиотека *events*
|
||||
|
||||
```lua
|
||||
events.on(code: str, handler: function)
|
||||
```
|
||||
|
||||
Добавляет обработчик события по его коду, не ограничиваясь стандартными.
|
||||
|
||||
```lua
|
||||
events.reset(code: str, [опционально] handler: function)
|
||||
```
|
||||
|
||||
Удаляет событие, добавляя обработчик, если указан.
|
||||
|
||||
```lua
|
||||
events.emit(code: str, args...) -> bool
|
||||
```
|
||||
|
||||
Генерирует событие по коду. Если событие не существует, ничего не произойдет.
|
||||
Существование события определяется наличием обработчиков.
|
||||
|
||||
```lua
|
||||
events.remove_by_prefix(packid: str)
|
||||
```
|
||||
|
||||
Удаляет все события с префиксом `packid:`. Вы выходе из мира выгружаются события всех паков, включая `core:`.
|
||||
|
||||
@ -70,6 +70,12 @@ input.is_active(bindname: str) -> bool
|
||||
|
||||
Проверяет активность привязки.
|
||||
|
||||
```python
|
||||
input.set_enabled(bindname: str, flag: bool)
|
||||
```
|
||||
|
||||
Включает/выключает привязку до выхода из мира.
|
||||
|
||||
```python
|
||||
input.is_pressed(code: str) -> bool
|
||||
```
|
||||
|
||||
@ -72,15 +72,13 @@
|
||||
|
||||
## Структуры
|
||||
|
||||
Структура - набор правил по вставке фрагмента в мир генератором. На данный момент не имеет свойств, создаваясь в виде пустых объектов в файле `generators/имя_генератора.files/structures.json`. Пример:
|
||||
```lua
|
||||
{
|
||||
"tree0": {},
|
||||
"tree1": {},
|
||||
"tree2": {},
|
||||
"tower": {},
|
||||
"coal_ore0": {}
|
||||
}
|
||||
Структура - набор правил по вставке фрагмента в мир генератором. На данный момент не имеет свойств, создаваясь в виде пустых объектов в файле `generators/имя_генератора.files/structures.toml`. Пример:
|
||||
```toml
|
||||
tree0 = {}
|
||||
tree1 = {}
|
||||
tree2 = {}
|
||||
tower = {}
|
||||
coal_ore0 = {}
|
||||
```
|
||||
|
||||
На данный момент, имя структуры должно совпадать с именем использованного фрагмента.
|
||||
@ -136,7 +134,7 @@ structures = [
|
||||
- block - блок растения
|
||||
- structure-chance - вероятность генерации малой структуры на блоке поверхности.
|
||||
- structures - структуры, случайно расставляемые на поверхности.
|
||||
- name - имя структуры, объявленной в `structures.json`.
|
||||
- name - имя структуры, объявленной в `structures.toml`.
|
||||
- weight - вес, напрямую влияющий на шанс выбора конкретной структуры.
|
||||
|
||||
### Параметры биомов
|
||||
@ -305,6 +303,7 @@ map:resize(ширина, высота, интерполяция)
|
||||
Доступные режимы интерполяции:
|
||||
- 'nearest' - без интерполяции
|
||||
- 'linear' - билинейная интерполяция
|
||||
- 'cubic' - бикубическая интерполяция
|
||||
|
||||
### heightmap:crop(...)
|
||||
|
||||
@ -356,7 +355,15 @@ generation.save_fragment(
|
||||
|
||||
Размер фрагмента доступен как свойство `size`.
|
||||
|
||||
Фрагмент может быть обрезан до размеров содержимого (воздух игнорируется) вызовом метода `fragment:crop()`.
|
||||
### Методы
|
||||
|
||||
```lua
|
||||
-- Обрезает фрагмент до размеров содержимого
|
||||
fragment:crop()
|
||||
|
||||
-- Устанавливает фрагмент в мир на указанной позиции
|
||||
fragment:place(position: vec3, [опционально] rotation:int=0)
|
||||
```
|
||||
|
||||
## Генерация карты высот
|
||||
|
||||
|
||||
@ -100,6 +100,7 @@
|
||||
- `placeholder` - текст подстановки (используется если текстовое поле пусто)
|
||||
- `supplier` - поставщик текста (вызывается каждый кадр)
|
||||
- `consumer` - lua функция-приемник введенного текста. Вызывается только при завершении ввода
|
||||
- `sub-consumer` - lua функция-приемник вводимого текста. Вызывается во время ввода или удаления текста.
|
||||
- `autoresize` - автоматическое изменение размера элемента (по-умолчанию - false). Не влияет на размер шрифта.
|
||||
- `multiline` - разрешает отображение многострочного текста.
|
||||
- `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true")
|
||||
|
||||
109
doc/specs/vec3_model_spec.md
Normal file
109
doc/specs/vec3_model_spec.md
Normal file
@ -0,0 +1,109 @@
|
||||
# VEC3 format specification
|
||||
|
||||
3D models binary format.
|
||||
|
||||
Byteorder: little-endian
|
||||
|
||||
## Syntax
|
||||
|
||||
```cpp
|
||||
enum AttributeType:uint8 {
|
||||
POSITION = 0,
|
||||
UV,
|
||||
NORMAL,
|
||||
COLOR,
|
||||
};
|
||||
sizeof(AttributeType) == 1;
|
||||
|
||||
struct VertexAttribute {
|
||||
AttributeType type; // data type is infered from attribute type
|
||||
uint8 flags;
|
||||
uint32 size;
|
||||
float data[]; // if compressed, first 4 bytes of compressed data is decompressed size
|
||||
};
|
||||
sizeof(VertexAttribute) == 6; // + dynamic data array
|
||||
|
||||
struct Mesh {
|
||||
uint32 triangle_count; // number of mesh triangles
|
||||
uint16 material_id;
|
||||
uint16 flags;
|
||||
uint16 attribute_count;
|
||||
VertexAttribute attributes[];
|
||||
uint8 indices[]; // if compressed, first 4 bytes of compressed data is compressed buffer size
|
||||
};
|
||||
sizeof(Mesh) == 10; // + dynamic attributes array + dynamic indices array
|
||||
|
||||
struct Model {
|
||||
uint16 name_len;
|
||||
vec3 origin;
|
||||
uint32 mesh_count;
|
||||
Mesh meshes[];
|
||||
char name[];
|
||||
};
|
||||
sizeof(Model) == 18; // + dynamic Mesh array + name length
|
||||
|
||||
struct Material {
|
||||
uint16 flags;
|
||||
uint16 name_len;
|
||||
char name[];
|
||||
};
|
||||
sizeof(Material) == 4; // + dynamic sized string
|
||||
|
||||
struct Header {
|
||||
char[8] ident; // "\0\0VEC3\0\0"
|
||||
uint16 version; // current is 1
|
||||
uint16 reserved; // 0x0000
|
||||
};
|
||||
sizeof(Header) == 12;
|
||||
|
||||
struct Body {
|
||||
uint16 material_count
|
||||
uint16 model_count
|
||||
Material materials[];
|
||||
Model models[];
|
||||
};
|
||||
sizeof(Body) == 4; // + dynamic models array + dynamic materials array
|
||||
|
||||
```
|
||||
|
||||
\* vertex data: positions are global. Model origins used to make it local.
|
||||
|
||||
vertex - is a set of vertex data section entries indices divided by stride, starting from 0 (section first entry).
|
||||
|
||||
Example: in file having sections (coordinates, texture_coordinates, normal) vertex is a set of 3 indices ordered the
|
||||
same way as sections stored in the file.
|
||||
|
||||
## Vertex Data section tags
|
||||
|
||||
All sections are optional.
|
||||
|
||||
| Value | Name | Stride (bytes) | Description |
|
||||
| ----- | ------------------- | -------------- | --------------------------- |
|
||||
| %x01 | Coordinates | 12 | vertex position |
|
||||
| %x02 | Texture coordinates | 8 | vertex texture coordinates |
|
||||
| %x03 | Normals | 12 | vertex normal vector |
|
||||
| %x04 | Color | 16 | vertex RGBA color (0.0-1.0) |
|
||||
|
||||
VertexAttribute flags:
|
||||
|
||||
| Value | Name |
|
||||
| ----- | ---------------- |
|
||||
| %x01 | ZLib compression |
|
||||
|
||||
## Mesh
|
||||
|
||||
Mesh flags:
|
||||
|
||||
| Value | Name |
|
||||
| ----- | ----------------------------------- |
|
||||
| %x01 | Indices ZLib compression |
|
||||
| %x02 | Use 16 bit indices instead of 8 bit |
|
||||
|
||||
## Material
|
||||
|
||||
Material flags:
|
||||
|
||||
| Bit offset | Description |
|
||||
|------------|-------------|
|
||||
| 0 | Shadeless |
|
||||
| 1-7 | Reserved |
|
||||
@ -16,4 +16,5 @@ player.attack="mouse:left"
|
||||
player.build="mouse:right"
|
||||
player.pick="mouse:middle"
|
||||
player.drop="key:q"
|
||||
player.fast_interaction="key:x"
|
||||
hud.inventory="key:tab"
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
{
|
||||
"texture": "water",
|
||||
"overlay-texture": "blocks:water",
|
||||
"draw-group": 3,
|
||||
"light-passing": true,
|
||||
"sky-light-passing": false,
|
||||
"obstacle": false,
|
||||
"selectable": false,
|
||||
"replaceable": true
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
o Cube
|
||||
v 0.5 -0.5 -0.5
|
||||
v 0.5 -0.5 0.5
|
||||
v -0.5 -0.5 0.5
|
||||
v -0.5 -0.5 -0.5
|
||||
v 0.5 0.5 -0.5
|
||||
v 0.5 0.5 0.5
|
||||
v -0.5 0.5 0.5
|
||||
v -0.5 0.5 -0.5
|
||||
vt 0.0 0.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 1.0
|
||||
vt 0.0 0.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 1.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 0.0
|
||||
vt 1.0 0.0
|
||||
vt 0.0 1.0
|
||||
vt 0.0 0.0
|
||||
vt 0.0 1.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 1.0
|
||||
vt 0.0 0.0
|
||||
vn 0.0 -1.0 0.0
|
||||
vn 0.0 1.0 0.0
|
||||
vn 1.0 -0.0 0.0
|
||||
vn -1.0 -0.0 -0.0
|
||||
vn 0.0 0.0 -1.0
|
||||
vn -0.0 -0.0 1.0
|
||||
usemtl $2
|
||||
s off
|
||||
f 1/1/1 2/2/1 3/3/1 4/4/1
|
||||
usemtl $3
|
||||
f 5/5/2 8/6/2 7/7/2 6/8/2
|
||||
usemtl $0
|
||||
f 1/9/3 5/10/3 6/8/3 2/11/3
|
||||
usemtl $1
|
||||
f 3/12/4 7/7/4 8/13/4 4/14/4
|
||||
usemtl $4
|
||||
f 5/15/5 1/1/5 4/16/5 8/17/5
|
||||
usemtl $5
|
||||
f 2/2/6 6/18/6 7/19/6 3/20/6
|
||||
@ -1,48 +0,0 @@
|
||||
o Cube
|
||||
v 0.125 -0.125 -0.125
|
||||
v 0.125 -0.125 0.125
|
||||
v -0.125 -0.125 0.125
|
||||
v -0.125 -0.125 -0.125
|
||||
v 0.125 0.125 -0.125
|
||||
v 0.125 0.125 0.125
|
||||
v -0.125 0.125 0.125
|
||||
v -0.125 0.125 -0.125
|
||||
vt 0.0 0.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 1.0
|
||||
vt 0.0 0.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 1.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 0.0
|
||||
vt 1.0 0.0
|
||||
vt 0.0 1.0
|
||||
vt 0.0 0.0
|
||||
vt 0.0 1.0
|
||||
vt 1.0 0.0
|
||||
vt 1.0 1.0
|
||||
vt 1.0 1.0
|
||||
vt 0.0 1.0
|
||||
vt 0.0 0.0
|
||||
vn 0.0 -1.0 0.0
|
||||
vn 0.0 1.0 0.0
|
||||
vn 1.0 -0.0 0.0
|
||||
vn -1.0 -0.0 -0.0
|
||||
vn 0.0 0.0 -1.0
|
||||
vn -0.0 -0.0 1.0
|
||||
usemtl $2
|
||||
s off
|
||||
f 1/1/1 2/2/1 3/3/1 4/4/1
|
||||
usemtl $3
|
||||
f 5/5/2 8/6/2 7/7/2 6/8/2
|
||||
usemtl $0
|
||||
f 1/9/3 5/10/3 6/8/3 2/11/3
|
||||
usemtl $1
|
||||
f 3/12/4 7/7/4 8/13/4 4/14/4
|
||||
usemtl $4
|
||||
f 5/15/5 1/1/5 4/16/5 8/17/5
|
||||
usemtl $5
|
||||
f 2/2/6 6/18/6 7/19/6 3/20/6
|
||||
BIN
res/content/base/models/drop-block.vec3
Normal file
BIN
res/content/base/models/drop-block.vec3
Normal file
Binary file not shown.
@ -1,113 +0,0 @@
|
||||
o Cube
|
||||
v 0.282501 -0.000054 -0.282500
|
||||
v -0.282501 -0.000054 -0.282501
|
||||
v -0.282501 -0.000054 0.282500
|
||||
v 0.282500 -0.000054 0.282501
|
||||
v 0.282501 0.012502 -0.282500
|
||||
v -0.282501 0.012502 -0.282501
|
||||
v -0.282501 0.012502 0.282500
|
||||
v 0.282500 0.012502 0.282501
|
||||
v 0.282501 0.012502 -0.282500
|
||||
v 0.282500 0.012502 0.282501
|
||||
v -0.282501 0.012502 0.282500
|
||||
v -0.282501 0.012502 -0.282501
|
||||
v 0.282501 -0.000054 -0.282500
|
||||
v 0.282500 -0.000054 0.282501
|
||||
v -0.282501 -0.000054 0.282500
|
||||
v -0.282501 -0.000054 -0.282501
|
||||
v 0.282501 0.012502 -0.282500
|
||||
v -0.282501 0.012502 -0.282501
|
||||
v -0.282501 0.012502 0.282500
|
||||
v 0.282500 0.012502 0.282501
|
||||
v 0.282501 0.012502 -0.282500
|
||||
v 0.282500 0.012502 0.282501
|
||||
v -0.282501 0.012502 0.282500
|
||||
v -0.282501 0.012502 -0.282501
|
||||
v 0.282501 -0.015821 -0.282500
|
||||
v -0.282501 -0.015821 -0.282501
|
||||
v -0.282501 -0.015821 0.282500
|
||||
v 0.282500 -0.015821 0.282501
|
||||
v 0.282501 0.027439 -0.282500
|
||||
v -0.282501 0.027439 -0.282501
|
||||
v -0.282501 0.027439 0.282500
|
||||
v 0.282500 0.027439 0.282501
|
||||
v 0.282501 0.027439 -0.282500
|
||||
v 0.282500 0.027439 0.282501
|
||||
v -0.282501 0.027439 0.282500
|
||||
v -0.282501 0.027439 -0.282501
|
||||
v 0.282501 -0.015821 -0.282500
|
||||
v 0.282500 -0.015821 0.282501
|
||||
v -0.282501 -0.015821 0.282500
|
||||
v -0.282501 -0.015821 -0.282501
|
||||
v 0.282501 0.027439 -0.282500
|
||||
v -0.282501 0.027439 -0.282501
|
||||
v -0.282501 0.027439 0.282500
|
||||
v 0.282500 0.027439 0.282501
|
||||
v 0.282501 0.027439 -0.282500
|
||||
v 0.282500 0.027439 0.282501
|
||||
v -0.282501 0.027439 0.282500
|
||||
v -0.282501 0.027439 -0.282501
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 1.000000 0.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 0.000000
|
||||
vn -0.0000 1.0000 0.0000
|
||||
vn 0.0000 -1.0000 -0.0000
|
||||
usemtl $0
|
||||
s 1
|
||||
f 1/1/1 2/2/1 3/3/1 4/4/1
|
||||
f 5/5/1 6/6/1 7/7/1 8/8/1
|
||||
f 9/9/2 10/10/2 11/11/2 12/12/2
|
||||
f 13/13/2 14/14/2 15/15/2 16/16/2
|
||||
f 17/17/1 18/18/1 19/19/1 20/20/1
|
||||
f 21/21/2 22/22/2 23/23/2 24/24/2
|
||||
f 25/25/1 26/26/1 27/27/1 28/28/1
|
||||
f 29/29/1 30/30/1 31/31/1 32/32/1
|
||||
f 33/33/2 34/34/2 35/35/2 36/36/2
|
||||
f 37/37/2 38/38/2 39/39/2 40/40/2
|
||||
f 41/41/1 42/42/1 43/43/1 44/44/1
|
||||
f 45/45/2 46/46/2 47/47/2 48/48/2
|
||||
@ -1,47 +0,0 @@
|
||||
# Blender v2.79 (sub 0) OBJ File: 'player.blend'
|
||||
# www.blender.org
|
||||
mtllib player-body.mtl
|
||||
o Cube.001
|
||||
v -0.125000 -0.900000 0.070903
|
||||
v -0.125000 -0.900000 -0.070903
|
||||
v 0.125000 -0.900000 -0.070903
|
||||
v 0.125000 -0.900000 0.070903
|
||||
v -0.125000 0.491919 0.070903
|
||||
v 0.125000 0.491919 0.070903
|
||||
v 0.125000 0.491919 -0.070903
|
||||
v -0.125000 0.491919 -0.070903
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.112175 0.434439
|
||||
vt 0.311556 0.434439
|
||||
vt 0.311556 0.633819
|
||||
vt 0.112175 0.633819
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vn 0.0000 -1.0000 0.0000
|
||||
vn 0.0000 1.0000 0.0000
|
||||
vn -1.0000 0.0000 0.0000
|
||||
vn -0.0000 -0.0000 -1.0000
|
||||
vn 1.0000 0.0000 0.0000
|
||||
vn 0.0000 0.0000 1.0000
|
||||
usemtl entities/player
|
||||
s 1
|
||||
f 1/1/1 2/2/1 3/3/1 4/4/1
|
||||
f 5/5/2 6/6/2 7/7/2 8/8/2
|
||||
f 1/1/3 5/9/3 8/10/3 2/11/3
|
||||
f 2/12/4 8/13/4 7/14/4 3/15/4
|
||||
f 3/16/5 7/17/5 6/18/5 4/4/5
|
||||
f 5/5/6 1/19/6 4/20/6 6/21/6
|
||||
BIN
res/content/base/models/player-body.vec3
Normal file
BIN
res/content/base/models/player-body.vec3
Normal file
Binary file not shown.
@ -1,42 +0,0 @@
|
||||
# Blender v2.79 (sub 0) OBJ File: 'player.blend'
|
||||
# www.blender.org
|
||||
mtllib player-hand.mtl
|
||||
o Cube.000_Cube.002
|
||||
v 0.062480 -0.613786 -0.062480
|
||||
v 0.062480 -0.613786 0.062480
|
||||
v -0.062480 -0.613786 0.062480
|
||||
v -0.062480 -0.613786 -0.062480
|
||||
v 0.062480 0.070352 -0.062480
|
||||
v -0.062480 0.070352 -0.062480
|
||||
v -0.062480 0.070352 0.062480
|
||||
v 0.062480 0.070352 0.062480
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.436482 0.280393
|
||||
vt 0.433740 0.937829
|
||||
vt 0.436146 0.914519
|
||||
vt 0.438665 0.292591
|
||||
vt 0.492515 0.918221
|
||||
vt 0.493194 0.293103
|
||||
vt 0.493371 0.941872
|
||||
vt 0.494058 0.280870
|
||||
vn 0.0000 -1.0000 0.0000
|
||||
vn 0.0000 1.0000 -0.0000
|
||||
vn 1.0000 -0.0000 0.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vn -1.0000 0.0000 0.0000
|
||||
vn 0.0000 0.0000 -1.0000
|
||||
usemtl entities/player
|
||||
s 1
|
||||
f 1/1/1 2/2/1 3/3/1 4/4/1
|
||||
f 5/5/2 6/6/2 7/7/2 8/8/2
|
||||
f 1/9/3 5/10/3 8/11/3 2/12/3
|
||||
f 2/12/4 8/11/4 7/13/4 3/14/4
|
||||
f 3/14/5 7/13/5 6/15/5 4/16/5
|
||||
f 5/10/6 1/9/6 4/16/6 6/15/6
|
||||
BIN
res/content/base/models/player-hand.vec3
Normal file
BIN
res/content/base/models/player-hand.vec3
Normal file
Binary file not shown.
@ -1,48 +0,0 @@
|
||||
# Blender v2.79 (sub 0) OBJ File: 'player.blend'
|
||||
# www.blender.org
|
||||
mtllib player-head.mtl
|
||||
o Cube.002_Cube.003
|
||||
v -0.206512 0.031837 0.206512
|
||||
v -0.206512 0.444861 0.206512
|
||||
v -0.206512 0.444861 -0.206512
|
||||
v -0.206512 0.031837 -0.206512
|
||||
v 0.206512 0.444861 -0.206512
|
||||
v 0.206512 0.031837 -0.206512
|
||||
v 0.206512 0.444861 0.206512
|
||||
v 0.206512 0.031837 0.206512
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.735873 0.213345
|
||||
vt 0.735873 0.739780
|
||||
vt 0.209439 0.739780
|
||||
vt 0.209439 0.213345
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.209065
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.982503 0.209065
|
||||
vt 0.783122 0.009685
|
||||
vt 0.982503 0.009685
|
||||
vt 0.783122 0.209065
|
||||
vn -1.0000 -0.0000 -0.0000
|
||||
vn 0.0000 0.0000 -1.0000
|
||||
vn 1.0000 0.0000 0.0000
|
||||
vn -0.0000 -0.0000 1.0000
|
||||
vn 0.0000 -1.0000 -0.0000
|
||||
vn -0.0000 1.0000 0.0000
|
||||
usemtl entities/player
|
||||
s 1
|
||||
f 1/1/1 2/2/1 3/3/1 4/4/1
|
||||
f 4/5/2 3/6/2 5/7/2 6/8/2
|
||||
f 6/9/3 5/10/3 7/11/3 8/12/3
|
||||
f 8/13/4 7/14/4 2/15/4 1/16/4
|
||||
f 4/17/5 6/18/5 8/19/5 1/16/5
|
||||
f 5/20/6 3/21/6 2/15/6 7/22/6
|
||||
BIN
res/content/base/models/player-head.vec3
Normal file
BIN
res/content/base/models/player-head.vec3
Normal file
Binary file not shown.
@ -1,5 +1,3 @@
|
||||
local item_models = require "core:item_models"
|
||||
|
||||
local tsf = entity.transform
|
||||
local body = entity.rigidbody
|
||||
local rig = entity.skeleton
|
||||
@ -27,7 +25,7 @@ end
|
||||
|
||||
do -- setup visuals
|
||||
local matrix = mat4.idt()
|
||||
scale = item_models.setup(dropitem.id, rig, 0)
|
||||
rig:set_model(0, item.model_name(dropitem.id))
|
||||
local bodysize = math.min(scale[1], scale[2], scale[3]) * DROP_SCALE
|
||||
body:set_size({scale[1] * DROP_SCALE, bodysize, scale[3] * DROP_SCALE})
|
||||
mat4.mul(matrix, rotation, matrix)
|
||||
@ -38,9 +36,7 @@ end
|
||||
function on_grounded(force)
|
||||
local matrix = mat4.idt()
|
||||
mat4.rotate(matrix, {0, 1, 0}, math.random()*360, matrix)
|
||||
if model == "aabb" then
|
||||
mat4.rotate(matrix, {1, 0, 0}, 90, matrix)
|
||||
end
|
||||
mat4.rotate(matrix, {1, 0, 0}, 90, matrix)
|
||||
mat4.scale(matrix, scale, matrix)
|
||||
rig:set_matrix(0, matrix)
|
||||
inair = false
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
local item_models = require "core:item_models"
|
||||
|
||||
local tsf = entity.transform
|
||||
local body = entity.rigidbody
|
||||
local rig = entity.skeleton
|
||||
@ -9,12 +7,8 @@ local itemIndex = rig:index("item")
|
||||
|
||||
local function refresh_model(id)
|
||||
itemid = id
|
||||
if id == 0 then
|
||||
rig:set_model(itemIndex, "")
|
||||
else
|
||||
local scale = item_models.setup(itemid, rig, itemIndex)
|
||||
rig:set_matrix(itemIndex, mat4.scale(scale))
|
||||
end
|
||||
rig:set_model(itemIndex, item.model_name(itemid))
|
||||
rig:set_matrix(itemIndex, mat4.rotate({0, 1, 0}, -80))
|
||||
end
|
||||
|
||||
function on_render()
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.1 KiB |
@ -11,6 +11,13 @@
|
||||
gravity="bottom-left"
|
||||
></textbox>
|
||||
</container>
|
||||
<panel id="problemsLog"
|
||||
color="#00000010"
|
||||
position-func="gui.get_viewport()[1]-350,0"
|
||||
size-func="351,gui.get_viewport()[2]-40"
|
||||
padding="5,15,5,15">
|
||||
<label>@Problems</label>
|
||||
</panel>
|
||||
<textbox id='prompt'
|
||||
consumer='submit'
|
||||
margin='0'
|
||||
|
||||
@ -1,6 +1,14 @@
|
||||
history = session.get_entry("commands_history")
|
||||
history_pointer = #history
|
||||
|
||||
local warning_id = 0
|
||||
events.on("core:warning", function (wtype, text)
|
||||
document.problemsLog:add(gui.template("problem", {
|
||||
type="warning", text=wtype..": "..text, id=tostring(warning_id)
|
||||
}))
|
||||
warning_id = warning_id + 1
|
||||
end)
|
||||
|
||||
function setup_variables()
|
||||
local pid = hud.get_player()
|
||||
local x,y,z = player.get_pos(pid)
|
||||
@ -27,7 +35,7 @@ function on_history_up()
|
||||
end
|
||||
|
||||
function on_history_down()
|
||||
if history_pointer == #history-1 then
|
||||
if history_pointer >= #history-1 then
|
||||
return
|
||||
end
|
||||
history_pointer = history_pointer + 1
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
<!-- content is generated in script -->
|
||||
</panel>
|
||||
<button pos='15,430' size='440,40' onclick='menu:back()'>@Back</button>
|
||||
<button pos='460,430' size='440,40' onclick='core.open_folder("user:content")'>@Open content folder</button>
|
||||
|
||||
<panel id='content_info' pos='485,15' size='440,406' color='0' max-length='406' scrollable='true'>
|
||||
<label>@Creator</label>
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
|
||||
<panel margin='6' gravity='bottom-left' size='250' color='0' interval='1'>
|
||||
<button onclick='menu.page="languages"' id='langs_btn'>-</button>
|
||||
<button onclick='core.open_folder("user:")'>@Open data folder</button>
|
||||
<button id='s_rst' onclick='set_page("s_rst", "settings_reset")'>@Reset settings</button>
|
||||
<button onclick='menu:back()'>@Back</button>
|
||||
</panel>
|
||||
</container>
|
||||
|
||||
@ -11,6 +11,7 @@ function set_page(btn, page)
|
||||
document.s_dsp.enabled = true
|
||||
document.s_gfx.enabled = true
|
||||
document.s_ctl.enabled = true
|
||||
document.s_rst.enabled = true
|
||||
document[btn].enabled = false
|
||||
document.menu.page = page
|
||||
end
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
consumer='change_sensitivity'>
|
||||
</trackbar>
|
||||
<panel id='search_panel' size='380,60' padding='2' interval='1' color='#0000004C'>
|
||||
<textbox id='search_textbox' multiline='false' size='300,20' consumer='function(x) refresh_search() end'></textbox>
|
||||
<textbox id='search_textbox' multiline='false' size='300,20' sub-consumer='function(x) refresh_search() end'></textbox>
|
||||
</panel>
|
||||
<panel id='bindings_panel' size='380,204' padding='2' interval='1' max-length='300' color='#0000004C'>
|
||||
<!-- content is generated in script -->
|
||||
|
||||
@ -59,4 +59,6 @@ function on_open()
|
||||
create_checkbox("display.fullscreen", "Fullscreen")
|
||||
create_checkbox("camera.shaking", "Camera Shaking")
|
||||
create_checkbox("camera.inertia", "Camera Inertia")
|
||||
create_checkbox("camera.fov-effects", "Camera FOV Effects")
|
||||
create_checkbox("display.limit-fps-iconified", "Limit Background FPS")
|
||||
end
|
||||
|
||||
7
res/layouts/pages/settings_reset.xml
Normal file
7
res/layouts/pages/settings_reset.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<panel size='380, 0' color='#00000080' padding='8' context='menu'>
|
||||
<label multiline='false'>@Reset settings</label>
|
||||
<button onclick='reset("aud")'>@Audio</button>
|
||||
<button onclick='reset("dsp")'>@Display</button>
|
||||
<button onclick='reset("gfx")'>@Graphics</button>
|
||||
<button onclick='reset("ctl")'>@Controls</button>
|
||||
</panel>
|
||||
44
res/layouts/pages/settings_reset.xml.lua
Normal file
44
res/layouts/pages/settings_reset.xml.lua
Normal file
@ -0,0 +1,44 @@
|
||||
function reset(category)
|
||||
if category == "aud" then
|
||||
reset_audio()
|
||||
elseif category == "dsp" then
|
||||
reset_display()
|
||||
elseif category == "gfx" then
|
||||
reset_graphics()
|
||||
elseif category == "ctl" then
|
||||
reset_control()
|
||||
end
|
||||
end
|
||||
|
||||
function reset_setting(name)
|
||||
core.set_setting(name, core.get_setting_info(name).def)
|
||||
end
|
||||
|
||||
function reset_audio()
|
||||
reset_setting("audio.volume-master")
|
||||
reset_setting("audio.volume-regular")
|
||||
reset_setting("audio.volume-ui")
|
||||
reset_setting("audio.volume-ambient")
|
||||
reset_setting("audio.volume-music")
|
||||
end
|
||||
|
||||
function reset_display()
|
||||
reset_setting("camera.fov")
|
||||
reset_setting("display.framerate")
|
||||
reset_setting("display.fullscreen")
|
||||
reset_setting("camera.shaking")
|
||||
reset_setting("camera.inertia")
|
||||
reset_setting("camera.fov-effects")
|
||||
end
|
||||
|
||||
function reset_graphics()
|
||||
reset_setting("chunks.load-distance")
|
||||
reset_setting("chunks.load-speed")
|
||||
reset_setting("graphics.fog-curve")
|
||||
reset_setting("graphics.gamma")
|
||||
reset_setting("graphics.backlight")
|
||||
end
|
||||
|
||||
function reset_control()
|
||||
input.reset_bindings()
|
||||
end
|
||||
6
res/layouts/templates/problem.xml
Normal file
6
res/layouts/templates/problem.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<container id="%{id}" size="32" tooltip="%{text}">
|
||||
<image src="gui/%{type}" size="32"/>
|
||||
<label pos="36,2">%{text}</label>
|
||||
<image src="gui/cross" interactive="true" size="16" gravity="top-right"
|
||||
onclick="document['%{id}']:destruct()"></image>
|
||||
</container>
|
||||
BIN
res/models/block.vec3
Normal file
BIN
res/models/block.vec3
Normal file
Binary file not shown.
BIN
res/models/drop-item.vec3
Normal file
BIN
res/models/drop-item.vec3
Normal file
Binary file not shown.
@ -1,33 +0,0 @@
|
||||
local function setup(id, rig, index)
|
||||
rig:set_model(index, "drop-block")
|
||||
local icon = item.icon(id)
|
||||
local size = {1.0, 1.0, 1.0}
|
||||
if icon:find("^block%-previews%:") then
|
||||
local bid = block.index(icon:sub(16))
|
||||
model = block.get_model(bid)
|
||||
if model == "X" then
|
||||
size = {1.0, 0.3, 1.0}
|
||||
rig:set_model(index, "drop-item")
|
||||
rig:set_texture("$0", icon)
|
||||
else
|
||||
if model == "aabb" then
|
||||
local rot = block.get_rotation_profile(bid) == "pipe" and 4 or 0
|
||||
size = block.get_hitbox(bid, rot)[2]
|
||||
vec3.mul(size, 2.0, size)
|
||||
end
|
||||
local textures = block.get_textures(bid)
|
||||
for i,t in ipairs(textures) do
|
||||
rig:set_texture("$"..tostring(i-1), "blocks:"..textures[i])
|
||||
end
|
||||
end
|
||||
else
|
||||
size = {1.0, 0.3, 1.0}
|
||||
rig:set_model(index, "drop-item")
|
||||
rig:set_texture("$0", icon)
|
||||
end
|
||||
return size
|
||||
end
|
||||
|
||||
return {
|
||||
setup=setup,
|
||||
}
|
||||
@ -110,19 +110,39 @@ console.add_command(
|
||||
return "Time set to " .. args[1]
|
||||
end
|
||||
)
|
||||
|
||||
console.add_command(
|
||||
"blocks.fill id:str x:num~pos.x y:num~pos.y z:num~pos.z w:int h:int d:int",
|
||||
"time.daycycle operation:[stop|reset]",
|
||||
"Control time.daycycle",
|
||||
function(args, kwargs)
|
||||
local operation = args[1]
|
||||
if operation == "stop" then
|
||||
world.set_day_time_speed(0)
|
||||
return "Daily cycle has stopped"
|
||||
else
|
||||
world.set_day_time_speed(1.0)
|
||||
return "Daily cycle has started"
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
console.add_command(
|
||||
"blocks.fill id:str x1:int~pos.x y1:int~pos.y z1:int~pos.z "..
|
||||
"x2:int~pos.x y2:int~pos.y z2:int~pos.z",
|
||||
"Fill specified zone with blocks",
|
||||
function(args, kwargs)
|
||||
local name, x, y, z, w, h, d = unpack(args)
|
||||
local name, x1,y1,z1, x2,y2,z2 = unpack(args)
|
||||
local id = block.index(name)
|
||||
for ly = 0, h - 1 do
|
||||
for lz = 0, d - 1 do
|
||||
for lx = 0, w - 1 do
|
||||
block.set(x + lx, y + ly, z + lz, id)
|
||||
for y=y1,y2 do
|
||||
for z=z1,z2 do
|
||||
for x=x1,x2 do
|
||||
block.set(x, y, z, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
local w = math.floor(math.abs(x2-x1+1) + 0.5)
|
||||
local h = math.floor(math.abs(y2-y1+1) + 0.5)
|
||||
local d = math.floor(math.abs(z2-z1+1) + 0.5)
|
||||
return tostring(w * h * d) .. " blocks set"
|
||||
end
|
||||
)
|
||||
@ -151,22 +171,24 @@ console.add_command(
|
||||
)
|
||||
|
||||
console.add_command(
|
||||
"fragment.save x:int y:int z:int w:int h:int d:int name:str='untitled' crop:bool=false",
|
||||
"fragment.save x1:int~pos.x y1:int~pos.y z1:int~pos.z "..
|
||||
"x2:int~pos.x y2:int~pos.y z2:int~pos.z "..
|
||||
"name:str='untitled' crop:bool=false",
|
||||
"Save fragment",
|
||||
function(args, kwargs)
|
||||
local x = args[1]
|
||||
local y = args[2]
|
||||
local z = args[3]
|
||||
local x1 = args[1]
|
||||
local y1 = args[2]
|
||||
local z1 = args[3]
|
||||
|
||||
local w = args[4]
|
||||
local h = args[5]
|
||||
local d = args[6]
|
||||
local x2 = args[4]
|
||||
local y2 = args[5]
|
||||
local z2 = args[6]
|
||||
|
||||
local name = args[7]
|
||||
local crop = args[8]
|
||||
|
||||
local fragment = generation.create_fragment(
|
||||
{x, y, z}, {x + w, y + h, z + d}, crop, false
|
||||
{x1, y1, z1}, {x2, y2, z2}, crop, false
|
||||
)
|
||||
local filename = 'export:'..name..'.vox'
|
||||
generation.save_fragment(fragment, filename, crop)
|
||||
@ -187,3 +209,17 @@ console.add_command(
|
||||
" has been saved as "..file.resolve(filename))
|
||||
end
|
||||
)
|
||||
|
||||
console.add_command(
|
||||
"fragment.place file:str x:num~pos.x y:num~pos.y z:num~pos.z rotation:int=0",
|
||||
"Place fragment to the world",
|
||||
function(args, kwargs)
|
||||
local filename = args[1]
|
||||
local x = args[2]
|
||||
local y = args[3]
|
||||
local z = args[4]
|
||||
local rotation = args[5]
|
||||
local fragment = generation.load_fragment(filename)
|
||||
fragment:place({x, y, z}, rotation)
|
||||
end
|
||||
)
|
||||
|
||||
@ -9,22 +9,36 @@ function sleep(timesec)
|
||||
end
|
||||
end
|
||||
|
||||
-- events
|
||||
------------------------------------------------
|
||||
------------------- Events ---------------------
|
||||
------------------------------------------------
|
||||
events = {
|
||||
handlers = {}
|
||||
}
|
||||
|
||||
function events.on(event, func)
|
||||
-- why an array? length is always = 1
|
||||
-- FIXME: temporary fixed
|
||||
events.handlers[event] = {} -- events.handlers[event] or {}
|
||||
if events.handlers[event] == nil then
|
||||
events.handlers[event] = {}
|
||||
end
|
||||
table.insert(events.handlers[event], func)
|
||||
end
|
||||
|
||||
function events.reset(event, func)
|
||||
if func == nil then
|
||||
events.handlers[event] = nil
|
||||
else
|
||||
events.handlers[event] = {func}
|
||||
end
|
||||
end
|
||||
|
||||
function events.remove_by_prefix(prefix)
|
||||
for name, handlers in pairs(events.handlers) do
|
||||
if name:sub(1, #prefix) == prefix then
|
||||
events.handlers[name] = nil
|
||||
local actualname = name
|
||||
if type(name) == 'table' then
|
||||
actualname = name[1]
|
||||
end
|
||||
if actualname:sub(1, #prefix+1) == prefix..':' then
|
||||
events.handlers[actualname] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -34,11 +48,13 @@ function pack.unload(prefix)
|
||||
end
|
||||
|
||||
function events.emit(event, ...)
|
||||
result = nil
|
||||
if events.handlers[event] then
|
||||
for _, func in ipairs(events.handlers[event]) do
|
||||
result = result or func(...)
|
||||
end
|
||||
local result = nil
|
||||
local handlers = events.handlers[event]
|
||||
if handlers == nil then
|
||||
return nil
|
||||
end
|
||||
for _, func in ipairs(handlers) do
|
||||
result = result or func(...)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
@ -109,7 +109,8 @@ function string.explode(separator, str, withpattern)
|
||||
local current_pos = 1
|
||||
|
||||
for i = 1, string_len(str) do
|
||||
local start_pos, end_pos = string_find(str, separator, current_pos, not withpattern)
|
||||
local start_pos, end_pos = string_find(
|
||||
str, separator, current_pos, not withpattern)
|
||||
if (not start_pos) then break end
|
||||
ret[i] = string_sub(str, current_pos, start_pos - 1)
|
||||
current_pos = end_pos + 1
|
||||
@ -139,7 +140,7 @@ function string.formatted_time(seconds, format)
|
||||
end
|
||||
|
||||
function string.replace(str, tofind, toreplace)
|
||||
local tbl = string.Explode(tofind, str)
|
||||
local tbl = string.explode(tofind, str)
|
||||
if (tbl[1]) then return table.concat(tbl, toreplace) end
|
||||
return str
|
||||
end
|
||||
@ -159,6 +160,9 @@ function string.trim_left(s, char)
|
||||
return string.match(s, "^" .. char .. "*(.+)$") or s
|
||||
end
|
||||
|
||||
string.lower = utf8.lower
|
||||
string.upper = utf8.upper
|
||||
|
||||
local meta = getmetatable("")
|
||||
|
||||
function meta:__index(key)
|
||||
@ -234,6 +238,7 @@ function on_deprecated_call(name, alternatives)
|
||||
return
|
||||
end
|
||||
__warnings_hidden[name] = true
|
||||
events.emit("core:warning", "deprecated call", name)
|
||||
if alternatives then
|
||||
debug.warning("deprecated function called ("..name.."), use "..
|
||||
alternatives.." instead\n"..debug.traceback())
|
||||
|
||||
@ -16,7 +16,7 @@ void main() {
|
||||
float depth = (a_distance/256.0);
|
||||
float alpha = a_color.a * tex_color.a;
|
||||
// anyway it's any alpha-test alternative required
|
||||
if (alpha < 0.3f)
|
||||
if (alpha < 0.9f)
|
||||
discard;
|
||||
f_color = mix(a_color * tex_color, vec4(fogColor,1.0),
|
||||
min(1.0, pow(depth*u_fogFactor, u_fogCurve)));
|
||||
|
||||
@ -31,6 +31,7 @@ hud.inventory=Inventory
|
||||
player.pick=Pick Block
|
||||
player.attack=Attack / Break
|
||||
player.build=Place Block
|
||||
player.fast_interaction=Accelerated interaction
|
||||
player.flight=Flight
|
||||
player.noclip=No-clip
|
||||
player.drop=Drop Item
|
||||
|
||||
@ -38,7 +38,10 @@ menu.Page not found=Страница не найдена
|
||||
menu.Quit=Выход
|
||||
menu.Save and Quit to Menu=Сохранить и Выйти в Меню
|
||||
menu.Settings=Настройки
|
||||
menu.Reset settings=Сбросить настройки
|
||||
menu.Contents Menu=Меню контентпаков
|
||||
menu.Open data folder=Открыть папку данных
|
||||
menu.Open content folder=Открыть папку [content]
|
||||
|
||||
world.Seed=Зерно
|
||||
world.Name=Название
|
||||
@ -57,6 +60,7 @@ settings.Ambient=Фон
|
||||
settings.Backlight=Подсветка
|
||||
settings.Camera Shaking=Тряска Камеры
|
||||
settings.Camera Inertia=Инерция Камеры
|
||||
settings.Camera FOV Effects=Эффекты поля зрения
|
||||
settings.Fog Curve=Кривая Тумана
|
||||
settings.FOV=Поле Зрения
|
||||
settings.Fullscreen=Полный экран
|
||||
@ -72,6 +76,7 @@ settings.Regular Sounds=Обычные Звуки
|
||||
settings.UI Sounds=Звуки Интерфейса
|
||||
settings.V-Sync=Вертикальная Синхронизация
|
||||
settings.Key=Кнопка
|
||||
settings.Limit Background FPS=Ограничить фоновую частоту кадров
|
||||
|
||||
# Управление
|
||||
chunks.reload=Перезагрузить Чанки
|
||||
@ -88,6 +93,7 @@ hud.inventory=Инвентарь
|
||||
player.pick=Подобрать Блок
|
||||
player.attack=Атаковать / Сломать
|
||||
player.build=Поставить Блок
|
||||
player.fast_interaction=Ускоренное взаимодействие
|
||||
player.flight=Полёт
|
||||
player.drop=Выбросить Предмет
|
||||
camera.zoom=Приближение
|
||||
|
||||
@ -5,11 +5,13 @@
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "util/stringutil.hpp"
|
||||
#include "graphics/core/TextureAnimation.hpp"
|
||||
|
||||
class Assets;
|
||||
@ -84,6 +86,15 @@ public:
|
||||
return static_cast<T*>(found->second.get());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T& require(const std::string& name) const {
|
||||
T* asset = get<T>(name);
|
||||
if (asset == nullptr) {
|
||||
throw std::runtime_error(util::quote(name) + " not found");
|
||||
}
|
||||
return *asset;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::optional<const assets_map*> getMap() const {
|
||||
const auto& mapIter = assets.find(typeid(T));
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include "objects/rigging.hpp"
|
||||
#include "util/ThreadPool.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "items/ItemDef.hpp"
|
||||
#include "Assets.hpp"
|
||||
#include "assetload_funcs.hpp"
|
||||
|
||||
@ -212,12 +213,6 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
|
||||
loader.tryAddSound(material.breakSound);
|
||||
}
|
||||
|
||||
addLayouts(
|
||||
0,
|
||||
"core",
|
||||
loader.getPaths()->getMainRoot() / fs::path("layouts"),
|
||||
loader
|
||||
);
|
||||
for (auto& entry : content->getPacks()) {
|
||||
auto pack = entry.second.get();
|
||||
auto& info = pack->getInfo();
|
||||
@ -228,7 +223,11 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
|
||||
for (auto& entry : content->getSkeletons()) {
|
||||
auto& skeleton = *entry.second;
|
||||
for (auto& bone : skeleton.getBones()) {
|
||||
auto& model = bone->model.name;
|
||||
std::string model = bone->model.name;
|
||||
size_t pos = model.rfind('.');
|
||||
if (pos != std::string::npos) {
|
||||
model = model.substr(0, pos);
|
||||
}
|
||||
if (!model.empty()) {
|
||||
loader.add(
|
||||
AssetType::MODEL, MODELS_FOLDER + "/" + model, model
|
||||
@ -236,6 +235,15 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& [_, def] : content->items.getDefs()) {
|
||||
if (def->modelName.find(':') == std::string::npos) {
|
||||
loader.add(
|
||||
AssetType::MODEL,
|
||||
MODELS_FOLDER + "/" + def->modelName,
|
||||
def->modelName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "coders/imageio.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/obj.hpp"
|
||||
#include "coders/vec3.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "files/engine_paths.hpp"
|
||||
@ -23,6 +24,7 @@
|
||||
#include "graphics/core/Texture.hpp"
|
||||
#include "graphics/core/TextureAnimation.hpp"
|
||||
#include "objects/rigging.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "Assets.hpp"
|
||||
#include "AssetsLoader.hpp"
|
||||
|
||||
@ -39,18 +41,32 @@ static bool animation(
|
||||
Atlas* dstAtlas
|
||||
);
|
||||
|
||||
assetload::postfunc assetload::
|
||||
texture(AssetsLoader*, const ResPaths* paths, const std::string& filename, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||
std::shared_ptr<ImageData> image(
|
||||
imageio::read(paths->find(filename + ".png").u8string()).release()
|
||||
);
|
||||
return [name, image](auto assets) {
|
||||
assets->store(Texture::from(image.get()), name);
|
||||
};
|
||||
assetload::postfunc assetload::texture(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
auto actualFile = paths->find(filename + ".png").u8string();
|
||||
try {
|
||||
std::shared_ptr<ImageData> image(imageio::read(actualFile).release());
|
||||
return [name, image, actualFile](auto assets) {
|
||||
assets->store(Texture::from(image.get()), name);
|
||||
};
|
||||
} catch (const std::runtime_error& err) {
|
||||
logger.error() << actualFile << ": " << err.what();
|
||||
return [](auto) {};
|
||||
}
|
||||
}
|
||||
|
||||
assetload::postfunc assetload::
|
||||
shader(AssetsLoader*, const ResPaths* paths, const std::string& filename, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||
assetload::postfunc assetload::shader(
|
||||
AssetsLoader*,
|
||||
const ResPaths* paths,
|
||||
const std::string& filename,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
fs::path vertexFile = paths->find(filename + ".glslv");
|
||||
fs::path fragmentFile = paths->find(filename + ".glslf");
|
||||
|
||||
@ -181,8 +197,7 @@ assetload::postfunc assetload::sound(
|
||||
if (!fs::exists(variantFile)) {
|
||||
break;
|
||||
}
|
||||
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM)
|
||||
);
|
||||
baseSound->variants.emplace_back(audio::load_sound(variantFile, keepPCM));
|
||||
}
|
||||
|
||||
auto sound = baseSound.release();
|
||||
@ -191,21 +206,50 @@ assetload::postfunc assetload::sound(
|
||||
};
|
||||
}
|
||||
|
||||
assetload::postfunc assetload::
|
||||
model(AssetsLoader* loader, const ResPaths* paths, const std::string& file, const std::string& name, const std::shared_ptr<AssetCfg>&) {
|
||||
auto path = paths->find(file + ".obj");
|
||||
static void request_textures(AssetsLoader* loader, const model::Model& model) {
|
||||
for (auto& mesh : model.meshes) {
|
||||
if (mesh.texture.find('$') == std::string::npos) {
|
||||
auto filename = TEXTURES_FOLDER + "/" + mesh.texture;
|
||||
loader->add(
|
||||
AssetType::TEXTURE, filename, mesh.texture, nullptr
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assetload::postfunc assetload::model(
|
||||
AssetsLoader* loader,
|
||||
const ResPaths* paths,
|
||||
const std::string& file,
|
||||
const std::string& name,
|
||||
const std::shared_ptr<AssetCfg>&
|
||||
) {
|
||||
auto path = paths->find(file + ".vec3");
|
||||
if (fs::exists(path)) {
|
||||
auto bytes = files::read_bytes_buffer(path);
|
||||
auto modelVEC3 = std::make_shared<vec3::File>(vec3::load(path.u8string(), bytes));
|
||||
return [loader, name, modelVEC3=std::move(modelVEC3)](Assets* assets) {
|
||||
for (auto& [modelName, model] : modelVEC3->models) {
|
||||
request_textures(loader, model.model);
|
||||
std::string fullName = name;
|
||||
if (name != modelName) {
|
||||
fullName += "." + modelName;
|
||||
}
|
||||
assets->store(
|
||||
std::make_unique<model::Model>(model.model),
|
||||
fullName
|
||||
);
|
||||
logger.info() << "store model " << util::quote(modelName)
|
||||
<< " as " << util::quote(fullName);
|
||||
}
|
||||
};
|
||||
}
|
||||
path = paths->find(file + ".obj");
|
||||
auto text = files::read_string(path);
|
||||
try {
|
||||
auto model = obj::parse(path.u8string(), text).release();
|
||||
return [=](Assets* assets) {
|
||||
for (auto& mesh : model->meshes) {
|
||||
if (mesh.texture.find('$') == std::string::npos) {
|
||||
auto filename = TEXTURES_FOLDER + "/" + mesh.texture;
|
||||
loader->add(
|
||||
AssetType::TEXTURE, filename, mesh.texture, nullptr
|
||||
);
|
||||
}
|
||||
}
|
||||
request_textures(loader, *model);
|
||||
assets->store(std::unique_ptr<model::Model>(model), name);
|
||||
};
|
||||
} catch (const parsing_error& err) {
|
||||
|
||||
24
src/assets/assets_util.cpp
Normal file
24
src/assets/assets_util.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "assets_util.hpp"
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "graphics/core/Atlas.hpp"
|
||||
#include "graphics/core/Texture.hpp"
|
||||
|
||||
util::TextureRegion util::get_texture_region(
|
||||
const Assets& assets, const std::string& name, const std::string& fallback
|
||||
) {
|
||||
size_t sep = name.find(':');
|
||||
if (sep == std::string::npos) {
|
||||
return {assets.get<Texture>(name), UVRegion(0,0,1,1)};
|
||||
} else {
|
||||
auto atlas = assets.get<Atlas>(name.substr(0, sep));
|
||||
if (atlas) {
|
||||
if (auto reg = atlas->getIf(name.substr(sep+1))) {
|
||||
return {atlas->getTexture(), *reg};
|
||||
} else if (!fallback.empty()){
|
||||
return util::get_texture_region(assets, fallback, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
return {nullptr, UVRegion()};
|
||||
}
|
||||
21
src/assets/assets_util.hpp
Normal file
21
src/assets/assets_util.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "maths/UVRegion.hpp"
|
||||
|
||||
class Assets;
|
||||
class Texture;
|
||||
|
||||
namespace util {
|
||||
struct TextureRegion {
|
||||
const Texture* texture;
|
||||
UVRegion region;
|
||||
};
|
||||
|
||||
TextureRegion get_texture_region(
|
||||
const Assets& assets,
|
||||
const std::string& name,
|
||||
const std::string& fallback
|
||||
);
|
||||
}
|
||||
@ -107,6 +107,14 @@ void ByteReader::checkMagic(const char* data, size_t size) {
|
||||
pos += size;
|
||||
}
|
||||
|
||||
void ByteReader::get(char* dst, size_t size) {
|
||||
if (pos + size > this->size) {
|
||||
throw std::runtime_error("buffer underflow");
|
||||
}
|
||||
std::memcpy(dst, data+pos, size);
|
||||
pos += size;
|
||||
}
|
||||
|
||||
ubyte ByteReader::get() {
|
||||
if (pos == size) {
|
||||
throw std::runtime_error("buffer underflow");
|
||||
|
||||
@ -52,6 +52,8 @@ public:
|
||||
ByteReader(const ubyte* data);
|
||||
|
||||
void checkMagic(const char* data, size_t size);
|
||||
/// @brief Get N bytes
|
||||
void get(char* dst, size_t size);
|
||||
/// @brief Read one byte (unsigned 8 bit integer)
|
||||
ubyte get();
|
||||
/// @brief Read one byte (unsigned 8 bit integer) without pointer move
|
||||
|
||||
@ -360,6 +360,13 @@ std::string BasicParser::parseString(char quote, bool closeRequired) {
|
||||
ss << (char)parseSimpleInt(8);
|
||||
continue;
|
||||
}
|
||||
if (c == 'u') {
|
||||
int codepoint = parseSimpleInt(16);
|
||||
ubyte bytes[4];
|
||||
int size = util::encode_utf8(codepoint, bytes);
|
||||
ss.write(reinterpret_cast<char*>(bytes), size);
|
||||
continue;
|
||||
}
|
||||
switch (c) {
|
||||
case 'n': ss << '\n'; break;
|
||||
case 'r': ss << '\r'; break;
|
||||
|
||||
230
src/coders/vec3.cpp
Normal file
230
src/coders/vec3.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include "vec3.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "byte_utils.hpp"
|
||||
#include "util/data_io.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "graphics/core/Model.hpp"
|
||||
|
||||
inline constexpr int VERSION = 1;
|
||||
|
||||
inline constexpr int FLAG_ZLIB = 0x1;
|
||||
inline constexpr int FLAG_16BIT_INDICES = 0x2;
|
||||
|
||||
using namespace vec3;
|
||||
|
||||
vec3::Model::~Model() = default;
|
||||
|
||||
enum AttributeType {
|
||||
POSITION = 0,
|
||||
UV,
|
||||
NORMAL,
|
||||
COLOR
|
||||
};
|
||||
|
||||
struct VertexAttribute {
|
||||
AttributeType type;
|
||||
int flags;
|
||||
util::Buffer<float> data;
|
||||
|
||||
VertexAttribute() = default;
|
||||
|
||||
VertexAttribute(VertexAttribute&&) = default;
|
||||
|
||||
VertexAttribute& operator=(VertexAttribute&& o) {
|
||||
type = o.type;
|
||||
flags = o.flags;
|
||||
data = std::move(o.data);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
static VertexAttribute load_attribute(ByteReader& reader) {
|
||||
auto type = static_cast<AttributeType>(reader.get());
|
||||
int flags = reader.get();
|
||||
assert(type >= POSITION && flags <= COLOR);
|
||||
if (flags != 0) {
|
||||
throw std::runtime_error("attribute compression is not supported yet");
|
||||
}
|
||||
int size = reader.getInt32();
|
||||
|
||||
util::Buffer<float> data(size / sizeof(float));
|
||||
reader.get(reinterpret_cast<char*>(data.data()), size);
|
||||
if (dataio::is_big_endian()) {
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
data[i] = dataio::swap(data[i]);
|
||||
}
|
||||
}
|
||||
return VertexAttribute {type, flags, std::move(data)};
|
||||
}
|
||||
|
||||
static model::Mesh build_mesh(
|
||||
const std::vector<VertexAttribute>& attrs,
|
||||
const util::Buffer<uint16_t>& indices,
|
||||
const std::string& texture
|
||||
) {
|
||||
const glm::vec3* coords = nullptr;
|
||||
const glm::vec2* uvs = nullptr;
|
||||
const glm::vec3* normals = nullptr;
|
||||
|
||||
int coordsIndex, uvsIndex, normalsIndex;
|
||||
|
||||
for (int i = 0; i < attrs.size(); i++) {
|
||||
const auto& attr = attrs[i];
|
||||
switch (attr.type) {
|
||||
case POSITION:
|
||||
coords = reinterpret_cast<const glm::vec3*>(attr.data.data());
|
||||
coordsIndex = i;
|
||||
break;
|
||||
case UV:
|
||||
uvs = reinterpret_cast<const glm::vec2*>(attr.data.data());
|
||||
uvsIndex = i;
|
||||
break;
|
||||
case NORMAL:
|
||||
normals = reinterpret_cast<const glm::vec3*>(attr.data.data());
|
||||
normalsIndex = i;
|
||||
break;
|
||||
case COLOR: // unused
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::vector<model::Vertex> vertices;
|
||||
int attrsCount = attrs.size();
|
||||
int verticesCount = indices.size() / attrsCount;
|
||||
for (int i = 0; i < verticesCount; i++) {
|
||||
model::Vertex vertex {};
|
||||
if (coords) {
|
||||
vertex.coord = coords[indices[i * attrsCount + coordsIndex]];
|
||||
}
|
||||
if (uvs) {
|
||||
vertex.uv = uvs[indices[i * attrsCount + uvsIndex]];
|
||||
}
|
||||
if (normals) {
|
||||
vertex.normal = normals[indices[i * attrsCount + normalsIndex]];
|
||||
} else if (coords) {
|
||||
// Flat normal calculation
|
||||
int idx = (i / 3) * 3;
|
||||
auto a = coords[indices[idx * attrsCount + coordsIndex]];
|
||||
auto b = coords[indices[(idx + 1) * attrsCount + coordsIndex]];
|
||||
auto c = coords[indices[(idx + 2) * attrsCount + coordsIndex]];
|
||||
vertex.normal = glm::normalize(glm::cross(b - a, c - a));
|
||||
}
|
||||
vertices.push_back(std::move(vertex));
|
||||
}
|
||||
return model::Mesh {texture, std::move(vertices)};
|
||||
}
|
||||
|
||||
static model::Mesh load_mesh(
|
||||
ByteReader& reader, const std::vector<Material>& materials
|
||||
) {
|
||||
int triangleCount = reader.getInt32();
|
||||
int materialId = reader.getInt16();
|
||||
int flags = reader.getInt16();
|
||||
int attributeCount = reader.getInt16();
|
||||
if (flags == FLAG_ZLIB) {
|
||||
throw std::runtime_error("compression is not supported yet");
|
||||
}
|
||||
std::vector<VertexAttribute> attributes;
|
||||
for (int i = 0; i < attributeCount; i++) {
|
||||
attributes.push_back(load_attribute(reader));
|
||||
}
|
||||
|
||||
util::Buffer<uint16_t> indices(triangleCount * 3 * attributeCount);
|
||||
if ((flags & FLAG_16BIT_INDICES) == 0){
|
||||
util::Buffer<uint8_t> smallIndices(indices.size());
|
||||
reader.get(
|
||||
reinterpret_cast<char*>(smallIndices.data()),
|
||||
indices.size() * sizeof(uint8_t)
|
||||
);
|
||||
for (int i = 0; i < indices.size(); i++) {
|
||||
indices[i] = smallIndices[i];
|
||||
}
|
||||
} else {
|
||||
reader.get(
|
||||
reinterpret_cast<char*>(indices.data()),
|
||||
indices.size() * sizeof(uint16_t)
|
||||
);
|
||||
}
|
||||
if (dataio::is_big_endian()) {
|
||||
for (int i = 0; i < indices.size(); i++) {
|
||||
indices[i] = dataio::swap(indices[i]);
|
||||
}
|
||||
}
|
||||
return build_mesh(
|
||||
attributes,
|
||||
indices,
|
||||
materials.at(materialId).name
|
||||
);
|
||||
}
|
||||
|
||||
static Model load_model(
|
||||
ByteReader& reader, const std::vector<Material>& materials
|
||||
) {
|
||||
int nameLength = reader.getInt16();
|
||||
assert(nameLength >= 0);
|
||||
float x = reader.getFloat32();
|
||||
float y = reader.getFloat32();
|
||||
float z = reader.getFloat32();
|
||||
int meshCount = reader.getInt32();
|
||||
assert(meshCount >= 0);
|
||||
|
||||
std::vector<model::Mesh> meshes;
|
||||
for (int i = 0; i < meshCount; i++) {
|
||||
meshes.push_back(load_mesh(reader, materials));
|
||||
}
|
||||
util::Buffer<char> chars(nameLength);
|
||||
reader.get(chars.data(), nameLength);
|
||||
std::string name(chars.data(), nameLength);
|
||||
|
||||
glm::vec3 offset {x, y, z};
|
||||
for (auto& mesh : meshes) {
|
||||
for (auto& vertex : mesh.vertices) {
|
||||
vertex.coord -= offset;
|
||||
}
|
||||
}
|
||||
return Model {std::move(name), model::Model {std::move(meshes)}, {x, y, z}};
|
||||
}
|
||||
|
||||
static Material load_material(ByteReader& reader) {
|
||||
int flags = reader.getInt16();
|
||||
int nameLength = reader.getInt16();
|
||||
assert(nameLength >= 0);
|
||||
util::Buffer<char> chars(nameLength);
|
||||
reader.get(chars.data(), nameLength);
|
||||
std::string name(chars.data(), nameLength);
|
||||
return Material {flags, std::move(name)};
|
||||
}
|
||||
|
||||
File vec3::load(
|
||||
const std::string_view file, const util::Buffer<ubyte>& src
|
||||
) {
|
||||
ByteReader reader(src.data(), src.size());
|
||||
|
||||
// Header
|
||||
reader.checkMagic("\0\0VEC3\0\0", 8);
|
||||
int version = reader.getInt16();
|
||||
int reserved = reader.getInt16();
|
||||
if (version > VERSION) {
|
||||
throw std::runtime_error("unsupported VEC3 version");
|
||||
}
|
||||
assert(reserved == 0);
|
||||
|
||||
// Body
|
||||
int materialCount = reader.getInt16();
|
||||
int modelCount = reader.getInt16();
|
||||
assert(materialCount >= 0);
|
||||
assert(modelCount >= 0);
|
||||
|
||||
std::vector<Material> materials;
|
||||
for (int i = 0; i < materialCount; i++) {
|
||||
materials.push_back(load_material(reader));
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, Model> models;
|
||||
for (int i = 0; i < modelCount; i++) {
|
||||
Model model = load_model(reader, materials);
|
||||
models[model.name] = std::move(model);
|
||||
}
|
||||
return File {std::move(models), std::move(materials)};
|
||||
}
|
||||
40
src/coders/vec3.hpp
Normal file
40
src/coders/vec3.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "typedefs.hpp"
|
||||
#include "util/Buffer.hpp"
|
||||
#include "graphics/core/Model.hpp"
|
||||
|
||||
/// See /doc/specs/vec3_model_spec.md
|
||||
namespace vec3 {
|
||||
struct Material {
|
||||
int flags;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct Model {
|
||||
std::string name;
|
||||
model::Model model;
|
||||
glm::vec3 origin;
|
||||
|
||||
Model& operator=(Model&&) = default;
|
||||
|
||||
~Model();
|
||||
};
|
||||
|
||||
struct File {
|
||||
std::unordered_map<std::string, Model> models;
|
||||
std::vector<Material> materials;
|
||||
|
||||
File(File&&) = default;
|
||||
|
||||
File& operator=(File&&) = default;
|
||||
};
|
||||
|
||||
File load(const std::string_view file, const util::Buffer<ubyte>& src);
|
||||
}
|
||||
@ -44,6 +44,8 @@ std::unique_ptr<Content> ContentBuilder::build() {
|
||||
def.rt.hitboxes[i].push_back(aabb);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
def.rt.hitboxes->emplace_back(AABB(glm::vec3(1.0f)));
|
||||
}
|
||||
|
||||
blockDefsIndices.push_back(&def);
|
||||
|
||||
@ -326,6 +326,7 @@ void ContentLoader::loadBlock(
|
||||
root.at("ui-layout").get(def.uiLayout);
|
||||
root.at("inventory-size").get(def.inventorySize);
|
||||
root.at("tick-interval").get(def.tickInterval);
|
||||
root.at("overlay-texture").get(def.overlayTexture);
|
||||
|
||||
if (root.has("fields")) {
|
||||
def.dataStruct = std::make_unique<StructLayout>();
|
||||
@ -418,17 +419,18 @@ void ContentLoader::loadItem(
|
||||
std::string iconTypeStr = "";
|
||||
root.at("icon-type").get(iconTypeStr);
|
||||
if (iconTypeStr == "none") {
|
||||
def.iconType = item_icon_type::none;
|
||||
def.iconType = ItemIconType::NONE;
|
||||
} else if (iconTypeStr == "block") {
|
||||
def.iconType = item_icon_type::block;
|
||||
def.iconType = ItemIconType::BLOCK;
|
||||
} else if (iconTypeStr == "sprite") {
|
||||
def.iconType = item_icon_type::sprite;
|
||||
def.iconType = ItemIconType::SPRITE;
|
||||
} else if (iconTypeStr.length()) {
|
||||
logger.error() << name << ": unknown icon type" << iconTypeStr;
|
||||
}
|
||||
root.at("icon").get(def.icon);
|
||||
root.at("placing-block").get(def.placingBlock);
|
||||
root.at("script-name").get(def.scriptName);
|
||||
root.at("model-name").get(def.modelName);
|
||||
root.at("stack-size").get(def.stackSize);
|
||||
|
||||
// item light emission [r, g, b] where r,g,b in range [0..15]
|
||||
@ -532,7 +534,7 @@ void ContentLoader::loadBlock(
|
||||
auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX);
|
||||
item.generated = true;
|
||||
item.caption = def.caption;
|
||||
item.iconType = item_icon_type::block;
|
||||
item.iconType = ItemIconType::BLOCK;
|
||||
item.icon = full;
|
||||
item.placingBlock = full;
|
||||
|
||||
|
||||
@ -202,6 +202,16 @@ void ContentLoader::loadGenerator(
|
||||
map.at("biome-parameters").get(def.biomeParameters);
|
||||
map.at("biome-bpd").get(def.biomesBPD);
|
||||
map.at("heights-bpd").get(def.heightsBPD);
|
||||
std::string interpName;
|
||||
map.at("heights-interpolation").get(interpName);
|
||||
if (auto interp = InterpolationType_from(interpName)) {
|
||||
def.heightsInterpolation = *interp;
|
||||
}
|
||||
map.at("biomes-interpolation").get(interpName);
|
||||
if (auto interp = InterpolationType_from(interpName)) {
|
||||
def.biomesInterpolation = *interp;
|
||||
}
|
||||
|
||||
map.at("sea-level").get(def.seaLevel);
|
||||
map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius);
|
||||
if (map.has("heightmap-inputs")) {
|
||||
|
||||
@ -25,13 +25,13 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
|
||||
}
|
||||
{
|
||||
ItemDef& item = builder->items.create(CORE_EMPTY);
|
||||
item.iconType = item_icon_type::none;
|
||||
item.iconType = ItemIconType::NONE;
|
||||
}
|
||||
|
||||
auto bindsFile = paths->getResourcesFolder()/fs::path("bindings.toml");
|
||||
if (fs::is_regular_file(bindsFile)) {
|
||||
Events::loadBindings(
|
||||
bindsFile.u8string(), files::read_string(bindsFile)
|
||||
bindsFile.u8string(), files::read_string(bindsFile), BindType::BIND
|
||||
);
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
|
||||
block.hitboxes = {AABB()};
|
||||
block.breakable = false;
|
||||
ItemDef& item = builder->items.create(CORE_OBSTACLE+".item");
|
||||
item.iconType = item_icon_type::block;
|
||||
item.iconType = ItemIconType::BLOCK;
|
||||
item.icon = CORE_OBSTACLE;
|
||||
item.placingBlock = CORE_OBSTACLE;
|
||||
item.caption = block.caption;
|
||||
@ -59,7 +59,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
|
||||
block.hitboxes = {AABB()};
|
||||
block.obstacle = false;
|
||||
ItemDef& item = builder->items.create(CORE_STRUCT_AIR+".item");
|
||||
item.iconType = item_icon_type::block;
|
||||
item.iconType = ItemIconType::BLOCK;
|
||||
item.icon = CORE_STRUCT_AIR;
|
||||
item.placingBlock = CORE_STRUCT_AIR;
|
||||
item.caption = block.caption;
|
||||
|
||||
@ -27,6 +27,8 @@ inline const std::string BIND_PLAYER_FLIGHT = "player.flight";
|
||||
inline const std::string BIND_PLAYER_ATTACK = "player.attack";
|
||||
inline const std::string BIND_PLAYER_BUILD = "player.build";
|
||||
inline const std::string BIND_PLAYER_PICK = "player.pick";
|
||||
inline const std::string BIND_PLAYER_FAST_INTERACTOIN =
|
||||
"player.fast_interaction";
|
||||
inline const std::string BIND_HUD_INVENTORY = "hud.inventory";
|
||||
|
||||
class EnginePaths;
|
||||
|
||||
@ -57,6 +57,10 @@ public:
|
||||
return value;
|
||||
}
|
||||
|
||||
const T& getDefault() const {
|
||||
return initial;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "frontend/menu.hpp"
|
||||
#include "frontend/screens/Screen.hpp"
|
||||
#include "frontend/screens/MenuScreen.hpp"
|
||||
#include "graphics/render/ModelsGenerator.hpp"
|
||||
#include "graphics/core/Batch2D.hpp"
|
||||
#include "graphics/core/DrawContext.hpp"
|
||||
#include "graphics/core/ImageData.hpp"
|
||||
@ -131,7 +132,7 @@ void Engine::loadControls() {
|
||||
if (fs::is_regular_file(controls_file)) {
|
||||
logger.info() << "loading controls";
|
||||
std::string text = files::read_string(controls_file);
|
||||
Events::loadBindings(controls_file.u8string(), text);
|
||||
Events::loadBindings(controls_file.u8string(), text, BindType::BIND);
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,8 +185,11 @@ void Engine::mainloop() {
|
||||
if (!Window::isIconified()) {
|
||||
renderFrame(batch);
|
||||
}
|
||||
Window::setFramerate(Window::isIconified() ? 20 :
|
||||
settings.display.framerate.get());
|
||||
Window::setFramerate(
|
||||
Window::isIconified() && settings.display.limitFpsIconified.get()
|
||||
? 20
|
||||
: settings.display.framerate.get()
|
||||
);
|
||||
|
||||
processPostRunnables();
|
||||
|
||||
@ -280,6 +284,17 @@ void Engine::loadAssets() {
|
||||
}
|
||||
}
|
||||
assets = std::move(new_assets);
|
||||
|
||||
if (content) {
|
||||
for (auto& [name, def] : content->items.getDefs()) {
|
||||
assets->store(
|
||||
std::make_unique<model::Model>(
|
||||
ModelsGenerator::generate(*def, *content, *assets)
|
||||
),
|
||||
name + ".model"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void load_configs(const fs::path& root) {
|
||||
@ -287,12 +302,14 @@ static void load_configs(const fs::path& root) {
|
||||
auto bindsFile = configFolder/fs::path("bindings.toml");
|
||||
if (fs::is_regular_file(bindsFile)) {
|
||||
Events::loadBindings(
|
||||
bindsFile.u8string(), files::read_string(bindsFile)
|
||||
bindsFile.u8string(), files::read_string(bindsFile), BindType::BIND
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::loadContent() {
|
||||
scripting::cleanup();
|
||||
|
||||
auto resdir = paths->getResourcesFolder();
|
||||
|
||||
std::vector<std::string> names;
|
||||
@ -338,6 +355,7 @@ void Engine::loadContent() {
|
||||
}
|
||||
|
||||
void Engine::resetContent() {
|
||||
scripting::cleanup();
|
||||
auto resdir = paths->getResourcesFolder();
|
||||
std::vector<PathsRoot> resRoots;
|
||||
{
|
||||
@ -388,6 +406,9 @@ double Engine::getDelta() const {
|
||||
}
|
||||
|
||||
void Engine::setScreen(std::shared_ptr<Screen> screen) {
|
||||
// unblock all bindings
|
||||
Events::enableBindings();
|
||||
// reset audio channels (stop all sources)
|
||||
audio::reset_channel(audio::get_channel_index("regular"));
|
||||
audio::reset_channel(audio::get_channel_index("ambient"));
|
||||
this->screen = std::move(screen);
|
||||
|
||||
@ -75,7 +75,11 @@ std::unique_ptr<ubyte[]> files::read_bytes(
|
||||
const fs::path& filename, size_t& length
|
||||
) {
|
||||
std::ifstream input(filename, std::ios::binary);
|
||||
if (!input.is_open()) return nullptr;
|
||||
if (!input.is_open()) {
|
||||
throw std::runtime_error(
|
||||
"could not to load file '" + filename.string() + "'"
|
||||
);
|
||||
}
|
||||
input.seekg(0, std::ios_base::end);
|
||||
length = input.tellg();
|
||||
input.seekg(0, std::ios_base::beg);
|
||||
@ -102,16 +106,11 @@ std::vector<ubyte> files::read_bytes(const fs::path& filename) {
|
||||
|
||||
std::string files::read_string(const fs::path& filename) {
|
||||
size_t size;
|
||||
std::unique_ptr<ubyte[]> bytes(read_bytes(filename, size));
|
||||
if (bytes == nullptr) {
|
||||
throw std::runtime_error(
|
||||
"could not to load file '" + filename.string() + "'"
|
||||
);
|
||||
}
|
||||
auto bytes = read_bytes(filename, size);
|
||||
return std::string((const char*)bytes.get(), size);
|
||||
}
|
||||
|
||||
bool files::write_string(const fs::path& filename, const std::string content) {
|
||||
bool files::write_string(const fs::path& filename, std::string_view content) {
|
||||
std::ofstream file(filename);
|
||||
if (!file) {
|
||||
return false;
|
||||
|
||||
@ -38,7 +38,7 @@ namespace files {
|
||||
uint append_bytes(const fs::path& file, const ubyte* data, size_t size);
|
||||
|
||||
/// @brief Write string to the file
|
||||
bool write_string(const fs::path& filename, const std::string content);
|
||||
bool write_string(const fs::path& filename, std::string_view content);
|
||||
|
||||
/// @brief Write dynamic data to the JSON file
|
||||
/// @param nice if true, human readable format will be used, otherwise
|
||||
|
||||
@ -51,6 +51,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) {
|
||||
builder.add("samples", &settings.display.samples);
|
||||
builder.add("framerate", &settings.display.framerate);
|
||||
builder.add("fullscreen", &settings.display.fullscreen);
|
||||
builder.add("limit-fps-iconified", &settings.display.limitFpsIconified);
|
||||
|
||||
builder.section("camera");
|
||||
builder.add("sensitivity", &settings.camera.sensitivity);
|
||||
@ -102,6 +103,26 @@ dv::value SettingsHandler::getValue(const std::string& name) const {
|
||||
}
|
||||
}
|
||||
|
||||
dv::value SettingsHandler::getDefault(const std::string& name) const {
|
||||
auto found = map.find(name);
|
||||
if (found == map.end()) {
|
||||
throw std::runtime_error("setting '" + name + "' does not exist");
|
||||
}
|
||||
auto setting = found->second;
|
||||
|
||||
if (auto number = dynamic_cast<NumberSetting*>(setting)) {
|
||||
return static_cast<number_t>(number->getDefault());
|
||||
} else if (auto integer = dynamic_cast<IntegerSetting*>(setting)) {
|
||||
return static_cast<integer_t>(integer->getDefault());
|
||||
} else if (auto flag = dynamic_cast<FlagSetting*>(setting)) {
|
||||
return flag->getDefault();
|
||||
} else if (auto string = dynamic_cast<StringSetting*>(setting)) {
|
||||
return string->getDefault();
|
||||
} else {
|
||||
throw std::runtime_error("type is not implemented for '" + name + "'");
|
||||
}
|
||||
}
|
||||
|
||||
std::string SettingsHandler::toString(const std::string& name) const {
|
||||
auto found = map.find(name);
|
||||
if (found == map.end()) {
|
||||
|
||||
@ -22,6 +22,7 @@ public:
|
||||
SettingsHandler(EngineSettings& settings);
|
||||
|
||||
dv::value getValue(const std::string& name) const;
|
||||
dv::value getDefault(const std::string& name) const;
|
||||
void setValue(const std::string& name, const dv::value& value);
|
||||
std::string toString(const std::string& name) const;
|
||||
Setting* getSetting(const std::string& name) const;
|
||||
|
||||
@ -37,10 +37,10 @@ LevelFrontend::LevelFrontend(
|
||||
auto soundsCamera = currentPlayer->currentCamera.get();
|
||||
if (soundsCamera == currentPlayer->spCamera.get() ||
|
||||
soundsCamera == currentPlayer->tpCamera.get()) {
|
||||
soundsCamera = currentPlayer->camera.get();
|
||||
soundsCamera = currentPlayer->fpCamera.get();
|
||||
}
|
||||
bool relative = player == currentPlayer &&
|
||||
soundsCamera == currentPlayer->camera.get();
|
||||
soundsCamera == currentPlayer->fpCamera.get();
|
||||
if (!relative) {
|
||||
pos = player->getPosition();
|
||||
}
|
||||
|
||||
@ -224,7 +224,7 @@ void Hud::processInput(bool visible) {
|
||||
setPause(true);
|
||||
}
|
||||
}
|
||||
if (!pause && Events::active(BIND_DEVTOOLS_CONSOLE)) {
|
||||
if (!pause && Events::jactive(BIND_DEVTOOLS_CONSOLE)) {
|
||||
showOverlay(assets->get<UiDocument>("core:console"), false);
|
||||
}
|
||||
if (!Window::isFocused() && !pause && !isInventoryOpen()) {
|
||||
|
||||
@ -37,7 +37,7 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr<Level> level)
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
menu->reset();
|
||||
|
||||
controller = std::make_unique<LevelController>(settings, std::move(level));
|
||||
controller = std::make_unique<LevelController>(engine, std::move(level));
|
||||
frontend = std::make_unique<LevelFrontend>(controller->getPlayer(), controller.get(), assets);
|
||||
|
||||
worldRenderer = std::make_unique<WorldRenderer>(engine, frontend.get(), controller->getPlayer());
|
||||
@ -48,7 +48,7 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr<Level> level)
|
||||
worldRenderer->clear();
|
||||
}));
|
||||
keepAlive(settings.camera.fov.observe([=](double value) {
|
||||
controller->getPlayer()->camera->setFov(glm::radians(value));
|
||||
controller->getPlayer()->fpCamera->setFov(glm::radians(value));
|
||||
}));
|
||||
keepAlive(Events::getBinding(BIND_CHUNKS_RELOAD).onactived.add([=](){
|
||||
controller->getLevel()->chunks->saveAndClear();
|
||||
@ -93,7 +93,7 @@ void LevelScreen::saveWorldPreview() {
|
||||
int previewSize = settings.ui.worldPreviewSize.get();
|
||||
|
||||
// camera special copy for world preview
|
||||
Camera camera = *player->camera;
|
||||
Camera camera = *player->fpCamera;
|
||||
camera.setFov(glm::radians(70.0f));
|
||||
|
||||
DrawContext pctx(nullptr, {Window::width, Window::height}, batch.get());
|
||||
@ -101,7 +101,7 @@ void LevelScreen::saveWorldPreview() {
|
||||
Viewport viewport(previewSize * 1.5, previewSize);
|
||||
DrawContext ctx(&pctx, viewport, batch.get());
|
||||
|
||||
worldRenderer->draw(ctx, &camera, false, true, 0.0f, postProcessing.get());
|
||||
worldRenderer->draw(ctx, camera, false, true, 0.0f, postProcessing.get());
|
||||
auto image = postProcessing->toImage();
|
||||
image->flipY();
|
||||
imageio::write(paths->resolve("world:preview.png").u8string(), image.get());
|
||||
@ -164,7 +164,9 @@ void LevelScreen::draw(float delta) {
|
||||
Viewport viewport(Window::width, Window::height);
|
||||
DrawContext ctx(nullptr, viewport, batch.get());
|
||||
|
||||
worldRenderer->draw(ctx, camera.get(), hudVisible, hud->isPause(), delta, postProcessing.get());
|
||||
worldRenderer->draw(
|
||||
ctx, *camera, hudVisible, hud->isPause(), delta, postProcessing.get()
|
||||
);
|
||||
|
||||
if (hudVisible) {
|
||||
hud->draw(ctx);
|
||||
|
||||
@ -75,7 +75,7 @@ void Batch2D::vertex(
|
||||
buffer[index++] = a;
|
||||
}
|
||||
|
||||
void Batch2D::texture(Texture* new_texture){
|
||||
void Batch2D::texture(const Texture* new_texture){
|
||||
if (currentTexture == new_texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ class Batch2D : public Flushable {
|
||||
std::unique_ptr<Texture> blank;
|
||||
size_t index;
|
||||
glm::vec4 color;
|
||||
Texture* currentTexture;
|
||||
const Texture* currentTexture;
|
||||
DrawPrimitive primitive = DrawPrimitive::triangle;
|
||||
UVRegion region {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
|
||||
@ -40,7 +40,7 @@ public:
|
||||
~Batch2D();
|
||||
|
||||
void begin();
|
||||
void texture(Texture* texture);
|
||||
void texture(const Texture* texture);
|
||||
void untexture();
|
||||
void setRegion(UVRegion region);
|
||||
void sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint);
|
||||
|
||||
@ -106,7 +106,7 @@ void Batch3D::face(
|
||||
tint.r, tint.g, tint.b, tint.a);
|
||||
}
|
||||
|
||||
void Batch3D::texture(Texture* new_texture){
|
||||
void Batch3D::texture(const Texture* new_texture){
|
||||
if (currentTexture == new_texture)
|
||||
return;
|
||||
flush();
|
||||
|
||||
@ -18,7 +18,7 @@ class Batch3D : public Flushable {
|
||||
std::unique_ptr<Texture> blank;
|
||||
size_t index;
|
||||
|
||||
Texture* currentTexture;
|
||||
const Texture* currentTexture;
|
||||
|
||||
void vertex(
|
||||
float x, float y, float z,
|
||||
@ -47,11 +47,36 @@ public:
|
||||
~Batch3D();
|
||||
|
||||
void begin();
|
||||
void texture(Texture* texture);
|
||||
void sprite(glm::vec3 pos, glm::vec3 up, glm::vec3 right, float w, float h, const UVRegion& uv, glm::vec4 tint);
|
||||
void xSprite(float w, float h, const UVRegion& uv, const glm::vec4 tint, bool shading=true);
|
||||
void cube(const glm::vec3 coords, const glm::vec3 size, const UVRegion(&texfaces)[6], const glm::vec4 tint, bool shading=true);
|
||||
void blockCube(const glm::vec3 size, const UVRegion(&texfaces)[6], const glm::vec4 tint, bool shading=true);
|
||||
void texture(const Texture* texture);
|
||||
void sprite(
|
||||
glm::vec3 pos,
|
||||
glm::vec3 up,
|
||||
glm::vec3 right,
|
||||
float w,
|
||||
float h,
|
||||
const UVRegion& uv,
|
||||
glm::vec4 tint
|
||||
);
|
||||
void xSprite(
|
||||
float w,
|
||||
float h,
|
||||
const UVRegion& uv,
|
||||
const glm::vec4 tint,
|
||||
bool shading = true
|
||||
);
|
||||
void cube(
|
||||
const glm::vec3 coords,
|
||||
const glm::vec3 size,
|
||||
const UVRegion (&texfaces)[6],
|
||||
const glm::vec4 tint,
|
||||
bool shading = true
|
||||
);
|
||||
void blockCube(
|
||||
const glm::vec3 size,
|
||||
const UVRegion (&texfaces)[6],
|
||||
const glm::vec4 tint,
|
||||
bool shading = true
|
||||
);
|
||||
void vertex(glm::vec3 pos, glm::vec2 uv, glm::vec4 tint);
|
||||
void point(glm::vec3 pos, glm::vec4 tint);
|
||||
void flush() override;
|
||||
|
||||
@ -30,10 +30,10 @@ Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat)
|
||||
}
|
||||
}
|
||||
|
||||
void Cubemap::bind(){
|
||||
void Cubemap::bind() const {
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
|
||||
}
|
||||
|
||||
void Cubemap::unbind() {
|
||||
void Cubemap::unbind() const {
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ class Cubemap : public GLTexture {
|
||||
public:
|
||||
Cubemap(uint width, uint height, ImageFormat format);
|
||||
|
||||
virtual void bind() override;
|
||||
virtual void unbind() override;
|
||||
virtual void bind() const override;
|
||||
virtual void unbind() const override;
|
||||
};
|
||||
|
||||
@ -33,11 +33,11 @@ GLTexture::~GLTexture() {
|
||||
glDeleteTextures(1, &id);
|
||||
}
|
||||
|
||||
void GLTexture::bind(){
|
||||
void GLTexture::bind() const {
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
}
|
||||
|
||||
void GLTexture::unbind() {
|
||||
void GLTexture::unbind() const {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ public:
|
||||
GLTexture(const ubyte* data, uint width, uint height, ImageFormat format);
|
||||
virtual ~GLTexture();
|
||||
|
||||
virtual void bind() override;
|
||||
virtual void unbind() override;
|
||||
virtual void bind() const override;
|
||||
virtual void unbind() const override;
|
||||
virtual void reload(const ubyte* data);
|
||||
|
||||
void setNearestFilter();
|
||||
|
||||
@ -29,6 +29,11 @@ void Mesh::addBox(glm::vec3 pos, glm::vec3 size) {
|
||||
addPlane(pos-X*size, Z*size, Y*size, -X);
|
||||
}
|
||||
|
||||
void Mesh::scale(const glm::vec3& size) {
|
||||
for (auto& vertex : vertices) {
|
||||
vertex.coord *= size;
|
||||
}
|
||||
}
|
||||
|
||||
void Model::clean() {
|
||||
meshes.erase(
|
||||
|
||||
@ -17,6 +17,7 @@ namespace model {
|
||||
|
||||
void addPlane(glm::vec3 pos, glm::vec3 right, glm::vec3 up, glm::vec3 norm);
|
||||
void addBox(glm::vec3 pos, glm::vec3 size);
|
||||
void scale(const glm::vec3& size);
|
||||
};
|
||||
|
||||
struct Model {
|
||||
|
||||
@ -17,8 +17,8 @@ public:
|
||||
|
||||
virtual ~Texture() {}
|
||||
|
||||
virtual void bind() = 0;
|
||||
virtual void unbind() = 0;
|
||||
virtual void bind() const = 0;
|
||||
virtual void unbind() const = 0;
|
||||
|
||||
virtual void reload(const ImageData& image) = 0;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "ModelBatch.hpp"
|
||||
|
||||
#include "assets/assets_util.hpp"
|
||||
#include "graphics/core/Mesh.hpp"
|
||||
#include "graphics/core/Model.hpp"
|
||||
#include "graphics/core/Atlas.hpp"
|
||||
@ -77,6 +78,7 @@ void ModelBatch::draw(const model::Mesh& mesh, const glm::mat4& matrix,
|
||||
const texture_names_map* varTextures,
|
||||
bool backlight) {
|
||||
glm::vec3 gpos = matrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
gpos += lightsOffset;
|
||||
light_t light = chunks->getLight(
|
||||
std::floor(gpos.x),
|
||||
std::floor(std::min(CHUNK_H-1.0f, gpos.y)),
|
||||
@ -137,9 +139,13 @@ void ModelBatch::render() {
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
void ModelBatch::setLightsOffset(const glm::vec3& offset) {
|
||||
lightsOffset = offset;
|
||||
}
|
||||
|
||||
void ModelBatch::setTexture(const std::string& name,
|
||||
const texture_names_map* varTextures) {
|
||||
if (name.at(0) == '$') {
|
||||
if (varTextures && name.at(0) == '$') {
|
||||
const auto& found = varTextures->find(name);
|
||||
if (found == varTextures->end()) {
|
||||
return setTexture(nullptr);
|
||||
@ -147,25 +153,13 @@ void ModelBatch::setTexture(const std::string& name,
|
||||
return setTexture(found->second, varTextures);
|
||||
}
|
||||
}
|
||||
size_t sep = name.find(':');
|
||||
if (sep == std::string::npos) {
|
||||
setTexture(assets->get<Texture>(name));
|
||||
} else {
|
||||
auto atlas = assets->get<Atlas>(name.substr(0, sep));
|
||||
if (atlas == nullptr) {
|
||||
setTexture(nullptr);
|
||||
} else {
|
||||
setTexture(atlas->getTexture());
|
||||
if (auto reg = atlas->getIf(name.substr(sep+1))) {
|
||||
region = *reg;
|
||||
} else {
|
||||
setTexture("blocks:notfound", varTextures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto textureRegion = util::get_texture_region(*assets, name, "blocks:notfound");
|
||||
setTexture(textureRegion.texture);
|
||||
region = textureRegion.region;
|
||||
}
|
||||
|
||||
void ModelBatch::setTexture(Texture* texture) {
|
||||
void ModelBatch::setTexture(const Texture* texture) {
|
||||
if (texture == nullptr) {
|
||||
texture = blank.get();
|
||||
}
|
||||
|
||||
@ -31,9 +31,10 @@ class ModelBatch {
|
||||
|
||||
Assets* assets;
|
||||
Chunks* chunks;
|
||||
Texture* texture = nullptr;
|
||||
const Texture* texture = nullptr;
|
||||
UVRegion region {0.0f, 0.0f, 1.0f, 1.0f};
|
||||
const EngineSettings* settings;
|
||||
glm::vec3 lightsOffset {};
|
||||
|
||||
static inline glm::vec3 SUN_VECTOR {0.411934f, 0.863868f, -0.279161f};
|
||||
|
||||
@ -71,7 +72,7 @@ class ModelBatch {
|
||||
bool backlight);
|
||||
void setTexture(const std::string& name,
|
||||
const texture_names_map* varTextures);
|
||||
void setTexture(Texture* texture);
|
||||
void setTexture(const Texture* texture);
|
||||
void flush();
|
||||
|
||||
struct DrawEntry {
|
||||
@ -96,4 +97,6 @@ public:
|
||||
const model::Model* model,
|
||||
const texture_names_map* varTextures);
|
||||
void render();
|
||||
|
||||
void setLightsOffset(const glm::vec3& offset);
|
||||
};
|
||||
|
||||
74
src/graphics/render/ModelsGenerator.cpp
Normal file
74
src/graphics/render/ModelsGenerator.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "ModelsGenerator.hpp"
|
||||
|
||||
#include "assets/Assets.hpp"
|
||||
#include "items/ItemDef.hpp"
|
||||
#include "voxels/Block.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
|
||||
static debug::Logger logger("models-generator");
|
||||
|
||||
static void configure_textures(
|
||||
model::Model& model,
|
||||
const Block& blockDef,
|
||||
const Assets& assets
|
||||
) {
|
||||
for (auto& mesh : model.meshes) {
|
||||
auto& texture = mesh.texture;
|
||||
if (texture.empty() || texture.at(0) != '$') {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
int index = std::stoi(texture.substr(1));
|
||||
texture = "blocks:"+blockDef.textureFaces.at(index);
|
||||
} catch (const std::invalid_argument& err) {
|
||||
} catch (const std::runtime_error& err) {
|
||||
logger.error() << err.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static model::Model create_flat_model(
|
||||
const std::string& texture, const Assets& assets
|
||||
) {
|
||||
auto model = assets.require<model::Model>("drop-item");
|
||||
for (auto& mesh : model.meshes) {
|
||||
if (mesh.texture == "$0") {
|
||||
mesh.texture = texture;
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
model::Model ModelsGenerator::generate(
|
||||
const ItemDef& def, const Content& content, const Assets& assets
|
||||
) {
|
||||
if (def.iconType == ItemIconType::BLOCK) {
|
||||
auto model = assets.require<model::Model>("block");
|
||||
const auto& blockDef = content.blocks.require(def.icon);
|
||||
if (blockDef.model == BlockModel::xsprite) {
|
||||
return create_flat_model(
|
||||
"blocks:" + blockDef.textureFaces.at(0), assets
|
||||
);
|
||||
}
|
||||
for (auto& mesh : model.meshes) {
|
||||
switch (blockDef.model) {
|
||||
case BlockModel::aabb: {
|
||||
glm::vec3 size = blockDef.hitboxes.at(0).size();
|
||||
float m = glm::max(size.x, glm::max(size.y, size.z));
|
||||
m = glm::min(1.0f, m);
|
||||
mesh.scale(size / m);
|
||||
break;
|
||||
} default:
|
||||
break;
|
||||
}
|
||||
mesh.scale(glm::vec3(0.3f));
|
||||
}
|
||||
configure_textures(model, blockDef, assets);
|
||||
return model;
|
||||
} else if (def.iconType == ItemIconType::SPRITE) {
|
||||
return create_flat_model(def.icon, assets);
|
||||
} else {
|
||||
return model::Model();
|
||||
}
|
||||
}
|
||||
14
src/graphics/render/ModelsGenerator.hpp
Normal file
14
src/graphics/render/ModelsGenerator.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "graphics/core/Model.hpp"
|
||||
|
||||
struct ItemDef;
|
||||
class Assets;
|
||||
class Content;
|
||||
|
||||
class ModelsGenerator {
|
||||
public:
|
||||
static model::Model generate(
|
||||
const ItemDef& def, const Content& content, const Assets& assets
|
||||
);
|
||||
};
|
||||
@ -58,11 +58,13 @@ Skybox::Skybox(uint size, Shader* shader)
|
||||
|
||||
Skybox::~Skybox() = default;
|
||||
|
||||
void Skybox::drawBackground(Camera* camera, Assets* assets, int width, int height) {
|
||||
auto backShader = assets->get<Shader>("background");
|
||||
void Skybox::drawBackground(
|
||||
const Camera& camera, const Assets& assets, int width, int height
|
||||
) {
|
||||
auto backShader = assets.get<Shader>("background");
|
||||
backShader->use();
|
||||
backShader->uniformMatrix("u_view", camera->getView(false));
|
||||
backShader->uniform1f("u_zoom", camera->zoom*camera->getFov()/(M_PI*0.5f));
|
||||
backShader->uniformMatrix("u_view", camera.getView(false));
|
||||
backShader->uniform1f("u_zoom", camera.zoom*camera.getFov()/(M_PI*0.5f));
|
||||
backShader->uniform1f("u_ar", float(width)/float(height));
|
||||
backShader->uniform1i("u_cubemap", 1);
|
||||
bind();
|
||||
@ -93,8 +95,8 @@ void Skybox::drawStars(float angle, float opacity) {
|
||||
|
||||
void Skybox::draw(
|
||||
const DrawContext& pctx,
|
||||
Camera* camera,
|
||||
Assets* assets,
|
||||
const Camera& camera,
|
||||
const Assets& assets,
|
||||
float daytime,
|
||||
float fog)
|
||||
{
|
||||
@ -107,9 +109,9 @@ void Skybox::draw(
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setBlendMode(BlendMode::addition);
|
||||
|
||||
auto p_shader = assets->get<Shader>("ui3d");
|
||||
auto p_shader = assets.get<Shader>("ui3d");
|
||||
p_shader->use();
|
||||
p_shader->uniformMatrix("u_projview", camera->getProjView(false));
|
||||
p_shader->uniformMatrix("u_projview", camera.getProjView(false));
|
||||
p_shader->uniformMatrix("u_apply", glm::mat4(1.0f));
|
||||
batch3d->begin();
|
||||
|
||||
@ -117,7 +119,7 @@ void Skybox::draw(
|
||||
float opacity = glm::pow(1.0f-fog, 7.0f);
|
||||
|
||||
for (auto& sprite : sprites) {
|
||||
batch3d->texture(assets->get<Texture>(sprite.texture));
|
||||
batch3d->texture(assets.get<Texture>(sprite.texture));
|
||||
|
||||
float sangle = daytime * float(M_PI)*2.0 + sprite.phase;
|
||||
float distance = sprite.distance;
|
||||
@ -136,6 +138,7 @@ void Skybox::draw(
|
||||
}
|
||||
|
||||
void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality) {
|
||||
float dayTime = t;
|
||||
DrawContext ctx = pctx.sub();
|
||||
ctx.setDepthMask(false);
|
||||
ctx.setDepthTest(false);
|
||||
@ -180,10 +183,12 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality)
|
||||
};
|
||||
t *= M_PI*2.0f;
|
||||
|
||||
lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f));
|
||||
shader->uniform1i("u_quality", quality);
|
||||
shader->uniform1f("u_mie", mie);
|
||||
shader->uniform1f("u_fog", mie - 1.0f);
|
||||
shader->uniform3f("u_lightDir", glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f)));
|
||||
shader->uniform3f("u_lightDir", lightDir);
|
||||
shader->uniform1f("u_dayTime", dayTime);
|
||||
for (uint face = 0; face < 6; face++) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap->getId(), 0);
|
||||
shader->uniform3f("u_xaxis", xaxs[face]);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user