Merge pull request #330 from MihailRis/item-models

Add item models
This commit is contained in:
MihailRis 2024-11-01 12:34:05 +03:00 committed by GitHub
commit f7ac76064b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
66 changed files with 541 additions and 557 deletions

View File

@ -37,7 +37,7 @@ jobs:
run: ./dev/fix_dylibs.sh VoxelEngine Release build run: ./dev/fix_dylibs.sh VoxelEngine Release build
- name: Run tests - name: Run tests
run: ctest --test-dir build run: ctest --output-on-failure --test-dir build
- name: Create DMG - name: Create DMG
run: | run: |

View File

@ -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/*) - **items** (generated from *png* files in *res/textures/items/*)
- **block** - block preview. Block ID must be specified in **icon** property. Example: *base:wood*. - **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 ## Behaviour
### *placing-block* ### *placing-block*

View File

@ -18,4 +18,10 @@ item.defs_count() -> int
-- Returns item icon name to use in 'src' property of an image element -- Returns item icon name to use in 'src' property of an image element
item.icon(itemid: int) -> str 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
``` ```

View File

@ -11,6 +11,12 @@
- items (генерируется из png файлов в `res/textures/items/`) - items (генерируется из png файлов в `res/textures/items/`)
- `block` - отображает предпросмотр блока. В icon указывается строковый id блока который нужно отображать. Пример `base:wood` - `block` - отображает предпросмотр блока. В icon указывается строковый id блока который нужно отображать. Пример `base:wood`
### Модель предмета - `model-name`
Имя модели предмета. Модель будет загружена автоматически.
Значение по-умолчанию - `packid:itemname.model`.
Если модель не указана, будет сгенерирована автоматическию
## Поведение ## Поведение
### Устанавливаемый блок - `placing-block` ### Устанавливаемый блок - `placing-block`

View File

@ -8,7 +8,7 @@ item.name(itemid: int) -> str
item.index(name: str) -> int item.index(name: str) -> int
-- Возвращает название предмета, отображаемое в интерфейсе. -- Возвращает название предмета, отображаемое в интерфейсе.
item.caption(blockid: int) -> str item.caption(itemid: int) -> str
-- Возвращает максимальный размер стопки для предмета. -- Возвращает максимальный размер стопки для предмета.
item.stack_size(itemid: int) -> int item.stack_size(itemid: int) -> int
@ -18,6 +18,12 @@ item.defs_count() -> int
-- Возвращает имя иконки предмета для использования в свойстве 'src' элемента image -- Возвращает имя иконки предмета для использования в свойстве 'src' элемента image
item.icon(itemid: int) -> str item.icon(itemid: int) -> str
-- Возвращает числовой id блока, назначенного как 'placing-block' или 0
item.placing_block(itemid: int) -> int
-- Возвращает значение свойства `model-name`
item.model_name(itemid: int) -> str
``` ```

View File

@ -1,5 +1,6 @@
{ {
"texture": "water", "texture": "water",
"overlay-texture": "blocks:water",
"draw-group": 3, "draw-group": 3,
"light-passing": true, "light-passing": true,
"sky-light-passing": false, "sky-light-passing": false,

View File

@ -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

Binary file not shown.

View File

@ -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

Binary file not shown.

View File

@ -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

View File

@ -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

Binary file not shown.

View File

@ -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

Binary file not shown.

View File

@ -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

Binary file not shown.

View File

@ -1,5 +1,3 @@
local item_models = require "core:item_models"
local tsf = entity.transform local tsf = entity.transform
local body = entity.rigidbody local body = entity.rigidbody
local rig = entity.skeleton local rig = entity.skeleton
@ -27,7 +25,7 @@ end
do -- setup visuals do -- setup visuals
local matrix = mat4.idt() 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 local bodysize = math.min(scale[1], scale[2], scale[3]) * DROP_SCALE
body:set_size({scale[1] * DROP_SCALE, bodysize, scale[3] * DROP_SCALE}) body:set_size({scale[1] * DROP_SCALE, bodysize, scale[3] * DROP_SCALE})
mat4.mul(matrix, rotation, matrix) mat4.mul(matrix, rotation, matrix)
@ -38,9 +36,7 @@ end
function on_grounded(force) function on_grounded(force)
local matrix = mat4.idt() local matrix = mat4.idt()
mat4.rotate(matrix, {0, 1, 0}, math.random()*360, matrix) mat4.rotate(matrix, {0, 1, 0}, math.random()*360, matrix)
if model == "aabb" then
mat4.rotate(matrix, {1, 0, 0}, 90, matrix) mat4.rotate(matrix, {1, 0, 0}, 90, matrix)
end
mat4.scale(matrix, scale, matrix) mat4.scale(matrix, scale, matrix)
rig:set_matrix(0, matrix) rig:set_matrix(0, matrix)
inair = false inair = false

View File

@ -1,5 +1,3 @@
local item_models = require "core:item_models"
local tsf = entity.transform local tsf = entity.transform
local body = entity.rigidbody local body = entity.rigidbody
local rig = entity.skeleton local rig = entity.skeleton
@ -9,12 +7,8 @@ local itemIndex = rig:index("item")
local function refresh_model(id) local function refresh_model(id)
itemid = id itemid = id
if id == 0 then rig:set_model(itemIndex, item.model_name(itemid))
rig:set_model(itemIndex, "") rig:set_matrix(itemIndex, mat4.rotate({0, 1, 0}, -80))
else
local scale = item_models.setup(itemid, rig, itemIndex)
rig:set_matrix(itemIndex, mat4.scale(scale))
end
end end
function on_render() function on_render()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
res/models/block.vec3 Normal file

Binary file not shown.

BIN
res/models/drop-item.vec3 Normal file

Binary file not shown.

View File

@ -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,
}

View File

@ -16,7 +16,7 @@ void main() {
float depth = (a_distance/256.0); float depth = (a_distance/256.0);
float alpha = a_color.a * tex_color.a; float alpha = a_color.a * tex_color.a;
// anyway it's any alpha-test alternative required // anyway it's any alpha-test alternative required
if (alpha < 0.3f) if (alpha < 0.9f)
discard; discard;
f_color = mix(a_color * tex_color, vec4(fogColor,1.0), f_color = mix(a_color * tex_color, vec4(fogColor,1.0),
min(1.0, pow(depth*u_fogFactor, u_fogCurve))); min(1.0, pow(depth*u_fogFactor, u_fogCurve)));

View File

@ -5,11 +5,13 @@
#include <optional> #include <optional>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <stdexcept>
#include <typeindex> #include <typeindex>
#include <typeinfo> #include <typeinfo>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "util/stringutil.hpp"
#include "graphics/core/TextureAnimation.hpp" #include "graphics/core/TextureAnimation.hpp"
class Assets; class Assets;
@ -84,6 +86,15 @@ public:
return static_cast<T*>(found->second.get()); 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> template <class T>
std::optional<const assets_map*> getMap() const { std::optional<const assets_map*> getMap() const {
const auto& mapIter = assets.find(typeid(T)); const auto& mapIter = assets.find(typeid(T));

View File

@ -16,6 +16,7 @@
#include "objects/rigging.hpp" #include "objects/rigging.hpp"
#include "util/ThreadPool.hpp" #include "util/ThreadPool.hpp"
#include "voxels/Block.hpp" #include "voxels/Block.hpp"
#include "items/ItemDef.hpp"
#include "Assets.hpp" #include "Assets.hpp"
#include "assetload_funcs.hpp" #include "assetload_funcs.hpp"
@ -240,6 +241,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
);
}
}
} }
} }

View 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()};
}

View 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
);
}

View File

@ -125,7 +125,6 @@ static model::Mesh load_mesh(
if (flags == FLAG_ZLIB) { if (flags == FLAG_ZLIB) {
throw std::runtime_error("compression is not supported yet"); throw std::runtime_error("compression is not supported yet");
} }
assert(flags == 0);
std::vector<VertexAttribute> attributes; std::vector<VertexAttribute> attributes;
for (int i = 0; i < attributeCount; i++) { for (int i = 0; i < attributeCount; i++) {
attributes.push_back(load_attribute(reader)); attributes.push_back(load_attribute(reader));

View File

@ -326,6 +326,7 @@ void ContentLoader::loadBlock(
root.at("ui-layout").get(def.uiLayout); root.at("ui-layout").get(def.uiLayout);
root.at("inventory-size").get(def.inventorySize); root.at("inventory-size").get(def.inventorySize);
root.at("tick-interval").get(def.tickInterval); root.at("tick-interval").get(def.tickInterval);
root.at("overlay-texture").get(def.overlayTexture);
if (root.has("fields")) { if (root.has("fields")) {
def.dataStruct = std::make_unique<StructLayout>(); def.dataStruct = std::make_unique<StructLayout>();
@ -418,17 +419,18 @@ void ContentLoader::loadItem(
std::string iconTypeStr = ""; std::string iconTypeStr = "";
root.at("icon-type").get(iconTypeStr); root.at("icon-type").get(iconTypeStr);
if (iconTypeStr == "none") { if (iconTypeStr == "none") {
def.iconType = item_icon_type::none; def.iconType = ItemIconType::NONE;
} else if (iconTypeStr == "block") { } else if (iconTypeStr == "block") {
def.iconType = item_icon_type::block; def.iconType = ItemIconType::BLOCK;
} else if (iconTypeStr == "sprite") { } else if (iconTypeStr == "sprite") {
def.iconType = item_icon_type::sprite; def.iconType = ItemIconType::SPRITE;
} else if (iconTypeStr.length()) { } else if (iconTypeStr.length()) {
logger.error() << name << ": unknown icon type" << iconTypeStr; logger.error() << name << ": unknown icon type" << iconTypeStr;
} }
root.at("icon").get(def.icon); root.at("icon").get(def.icon);
root.at("placing-block").get(def.placingBlock); root.at("placing-block").get(def.placingBlock);
root.at("script-name").get(def.scriptName); root.at("script-name").get(def.scriptName);
root.at("model-name").get(def.modelName);
root.at("stack-size").get(def.stackSize); root.at("stack-size").get(def.stackSize);
// item light emission [r, g, b] where r,g,b in range [0..15] // 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); auto& item = builder.items.create(full + BLOCK_ITEM_SUFFIX);
item.generated = true; item.generated = true;
item.caption = def.caption; item.caption = def.caption;
item.iconType = item_icon_type::block; item.iconType = ItemIconType::BLOCK;
item.icon = full; item.icon = full;
item.placingBlock = full; item.placingBlock = full;

View File

@ -25,7 +25,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
} }
{ {
ItemDef& item = builder->items.create(CORE_EMPTY); 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"); auto bindsFile = paths->getResourcesFolder()/fs::path("bindings.toml");
@ -43,7 +43,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
block.hitboxes = {AABB()}; block.hitboxes = {AABB()};
block.breakable = false; block.breakable = false;
ItemDef& item = builder->items.create(CORE_OBSTACLE+".item"); ItemDef& item = builder->items.create(CORE_OBSTACLE+".item");
item.iconType = item_icon_type::block; item.iconType = ItemIconType::BLOCK;
item.icon = CORE_OBSTACLE; item.icon = CORE_OBSTACLE;
item.placingBlock = CORE_OBSTACLE; item.placingBlock = CORE_OBSTACLE;
item.caption = block.caption; item.caption = block.caption;
@ -59,7 +59,7 @@ void corecontent::setup(EnginePaths* paths, ContentBuilder* builder) {
block.hitboxes = {AABB()}; block.hitboxes = {AABB()};
block.obstacle = false; block.obstacle = false;
ItemDef& item = builder->items.create(CORE_STRUCT_AIR+".item"); 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.icon = CORE_STRUCT_AIR;
item.placingBlock = CORE_STRUCT_AIR; item.placingBlock = CORE_STRUCT_AIR;
item.caption = block.caption; item.caption = block.caption;

View File

@ -20,6 +20,7 @@
#include "frontend/menu.hpp" #include "frontend/menu.hpp"
#include "frontend/screens/Screen.hpp" #include "frontend/screens/Screen.hpp"
#include "frontend/screens/MenuScreen.hpp" #include "frontend/screens/MenuScreen.hpp"
#include "graphics/render/ModelsGenerator.hpp"
#include "graphics/core/Batch2D.hpp" #include "graphics/core/Batch2D.hpp"
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
#include "graphics/core/ImageData.hpp" #include "graphics/core/ImageData.hpp"
@ -280,6 +281,17 @@ void Engine::loadAssets() {
} }
} }
assets = std::move(new_assets); 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) { static void load_configs(const fs::path& root) {

View File

@ -37,10 +37,10 @@ LevelFrontend::LevelFrontend(
auto soundsCamera = currentPlayer->currentCamera.get(); auto soundsCamera = currentPlayer->currentCamera.get();
if (soundsCamera == currentPlayer->spCamera.get() || if (soundsCamera == currentPlayer->spCamera.get() ||
soundsCamera == currentPlayer->tpCamera.get()) { soundsCamera == currentPlayer->tpCamera.get()) {
soundsCamera = currentPlayer->camera.get(); soundsCamera = currentPlayer->fpCamera.get();
} }
bool relative = player == currentPlayer && bool relative = player == currentPlayer &&
soundsCamera == currentPlayer->camera.get(); soundsCamera == currentPlayer->fpCamera.get();
if (!relative) { if (!relative) {
pos = player->getPosition(); pos = player->getPosition();
} }

View File

@ -48,7 +48,7 @@ LevelScreen::LevelScreen(Engine* engine, std::unique_ptr<Level> level)
worldRenderer->clear(); worldRenderer->clear();
})); }));
keepAlive(settings.camera.fov.observe([=](double value) { 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([=](){ keepAlive(Events::getBinding(BIND_CHUNKS_RELOAD).onactived.add([=](){
controller->getLevel()->chunks->saveAndClear(); controller->getLevel()->chunks->saveAndClear();
@ -93,7 +93,7 @@ void LevelScreen::saveWorldPreview() {
int previewSize = settings.ui.worldPreviewSize.get(); int previewSize = settings.ui.worldPreviewSize.get();
// camera special copy for world preview // camera special copy for world preview
Camera camera = *player->camera; Camera camera = *player->fpCamera;
camera.setFov(glm::radians(70.0f)); camera.setFov(glm::radians(70.0f));
DrawContext pctx(nullptr, {Window::width, Window::height}, batch.get()); DrawContext pctx(nullptr, {Window::width, Window::height}, batch.get());
@ -101,7 +101,7 @@ void LevelScreen::saveWorldPreview() {
Viewport viewport(previewSize * 1.5, previewSize); Viewport viewport(previewSize * 1.5, previewSize);
DrawContext ctx(&pctx, viewport, batch.get()); 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(); auto image = postProcessing->toImage();
image->flipY(); image->flipY();
imageio::write(paths->resolve("world:preview.png").u8string(), image.get()); 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); Viewport viewport(Window::width, Window::height);
DrawContext ctx(nullptr, viewport, batch.get()); 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) { if (hudVisible) {
hud->draw(ctx); hud->draw(ctx);

View File

@ -75,7 +75,7 @@ void Batch2D::vertex(
buffer[index++] = a; buffer[index++] = a;
} }
void Batch2D::texture(Texture* new_texture){ void Batch2D::texture(const Texture* new_texture){
if (currentTexture == new_texture) { if (currentTexture == new_texture) {
return; return;
} }

View File

@ -17,7 +17,7 @@ class Batch2D : public Flushable {
std::unique_ptr<Texture> blank; std::unique_ptr<Texture> blank;
size_t index; size_t index;
glm::vec4 color; glm::vec4 color;
Texture* currentTexture; const Texture* currentTexture;
DrawPrimitive primitive = DrawPrimitive::triangle; DrawPrimitive primitive = DrawPrimitive::triangle;
UVRegion region {0.0f, 0.0f, 1.0f, 1.0f}; UVRegion region {0.0f, 0.0f, 1.0f, 1.0f};
@ -40,7 +40,7 @@ public:
~Batch2D(); ~Batch2D();
void begin(); void begin();
void texture(Texture* texture); void texture(const Texture* texture);
void untexture(); void untexture();
void setRegion(UVRegion region); void setRegion(UVRegion region);
void sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint); void sprite(float x, float y, float w, float h, const UVRegion& region, glm::vec4 tint);

View File

@ -106,7 +106,7 @@ void Batch3D::face(
tint.r, tint.g, tint.b, tint.a); 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) if (currentTexture == new_texture)
return; return;
flush(); flush();

View File

@ -18,7 +18,7 @@ class Batch3D : public Flushable {
std::unique_ptr<Texture> blank; std::unique_ptr<Texture> blank;
size_t index; size_t index;
Texture* currentTexture; const Texture* currentTexture;
void vertex( void vertex(
float x, float y, float z, float x, float y, float z,
@ -47,11 +47,36 @@ public:
~Batch3D(); ~Batch3D();
void begin(); void begin();
void texture(Texture* texture); 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 sprite(
void xSprite(float w, float h, const UVRegion& uv, const glm::vec4 tint, bool shading=true); glm::vec3 pos,
void cube(const glm::vec3 coords, const glm::vec3 size, const UVRegion(&texfaces)[6], const glm::vec4 tint, bool shading=true); glm::vec3 up,
void blockCube(const glm::vec3 size, const UVRegion(&texfaces)[6], const glm::vec4 tint, bool shading=true); 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 vertex(glm::vec3 pos, glm::vec2 uv, glm::vec4 tint);
void point(glm::vec3 pos, glm::vec4 tint); void point(glm::vec3 pos, glm::vec4 tint);
void flush() override; void flush() override;

View File

@ -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); glBindTexture(GL_TEXTURE_CUBE_MAP, id);
} }
void Cubemap::unbind() { void Cubemap::unbind() const {
glBindTexture(GL_TEXTURE_CUBE_MAP, 0); glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
} }

View File

@ -7,6 +7,6 @@ class Cubemap : public GLTexture {
public: public:
Cubemap(uint width, uint height, ImageFormat format); Cubemap(uint width, uint height, ImageFormat format);
virtual void bind() override; virtual void bind() const override;
virtual void unbind() override; virtual void unbind() const override;
}; };

View File

@ -33,11 +33,11 @@ GLTexture::~GLTexture() {
glDeleteTextures(1, &id); glDeleteTextures(1, &id);
} }
void GLTexture::bind(){ void GLTexture::bind() const {
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
} }
void GLTexture::unbind() { void GLTexture::unbind() const {
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }

View File

@ -10,8 +10,8 @@ public:
GLTexture(const ubyte* data, uint width, uint height, ImageFormat format); GLTexture(const ubyte* data, uint width, uint height, ImageFormat format);
virtual ~GLTexture(); virtual ~GLTexture();
virtual void bind() override; virtual void bind() const override;
virtual void unbind() override; virtual void unbind() const override;
virtual void reload(const ubyte* data); virtual void reload(const ubyte* data);
void setNearestFilter(); void setNearestFilter();

View File

@ -29,6 +29,11 @@ void Mesh::addBox(glm::vec3 pos, glm::vec3 size) {
addPlane(pos-X*size, Z*size, Y*size, -X); 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() { void Model::clean() {
meshes.erase( meshes.erase(

View File

@ -17,6 +17,7 @@ namespace model {
void addPlane(glm::vec3 pos, glm::vec3 right, glm::vec3 up, glm::vec3 norm); void addPlane(glm::vec3 pos, glm::vec3 right, glm::vec3 up, glm::vec3 norm);
void addBox(glm::vec3 pos, glm::vec3 size); void addBox(glm::vec3 pos, glm::vec3 size);
void scale(const glm::vec3& size);
}; };
struct Model { struct Model {

View File

@ -17,8 +17,8 @@ public:
virtual ~Texture() {} virtual ~Texture() {}
virtual void bind() = 0; virtual void bind() const = 0;
virtual void unbind() = 0; virtual void unbind() const = 0;
virtual void reload(const ImageData& image) = 0; virtual void reload(const ImageData& image) = 0;

View File

@ -1,5 +1,6 @@
#include "ModelBatch.hpp" #include "ModelBatch.hpp"
#include "assets/assets_util.hpp"
#include "graphics/core/Mesh.hpp" #include "graphics/core/Mesh.hpp"
#include "graphics/core/Model.hpp" #include "graphics/core/Model.hpp"
#include "graphics/core/Atlas.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, const texture_names_map* varTextures,
bool backlight) { bool backlight) {
glm::vec3 gpos = matrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); glm::vec3 gpos = matrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
gpos += lightsOffset;
light_t light = chunks->getLight( light_t light = chunks->getLight(
std::floor(gpos.x), std::floor(gpos.x),
std::floor(std::min(CHUNK_H-1.0f, gpos.y)), std::floor(std::min(CHUNK_H-1.0f, gpos.y)),
@ -137,9 +139,13 @@ void ModelBatch::render() {
entries.clear(); entries.clear();
} }
void ModelBatch::setLightsOffset(const glm::vec3& offset) {
lightsOffset = offset;
}
void ModelBatch::setTexture(const std::string& name, void ModelBatch::setTexture(const std::string& name,
const texture_names_map* varTextures) { const texture_names_map* varTextures) {
if (name.at(0) == '$') { if (varTextures && name.at(0) == '$') {
const auto& found = varTextures->find(name); const auto& found = varTextures->find(name);
if (found == varTextures->end()) { if (found == varTextures->end()) {
return setTexture(nullptr); return setTexture(nullptr);
@ -147,25 +153,13 @@ void ModelBatch::setTexture(const std::string& name,
return setTexture(found->second, varTextures); return setTexture(found->second, varTextures);
} }
} }
size_t sep = name.find(':');
if (sep == std::string::npos) { auto textureRegion = util::get_texture_region(*assets, name, "blocks:notfound");
setTexture(assets->get<Texture>(name)); setTexture(textureRegion.texture);
} else { region = textureRegion.region;
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);
}
}
}
} }
void ModelBatch::setTexture(Texture* texture) { void ModelBatch::setTexture(const Texture* texture) {
if (texture == nullptr) { if (texture == nullptr) {
texture = blank.get(); texture = blank.get();
} }

View File

@ -31,9 +31,10 @@ class ModelBatch {
Assets* assets; Assets* assets;
Chunks* chunks; Chunks* chunks;
Texture* texture = nullptr; const Texture* texture = nullptr;
UVRegion region {0.0f, 0.0f, 1.0f, 1.0f}; UVRegion region {0.0f, 0.0f, 1.0f, 1.0f};
const EngineSettings* settings; const EngineSettings* settings;
glm::vec3 lightsOffset {};
static inline glm::vec3 SUN_VECTOR {0.411934f, 0.863868f, -0.279161f}; static inline glm::vec3 SUN_VECTOR {0.411934f, 0.863868f, -0.279161f};
@ -71,7 +72,7 @@ class ModelBatch {
bool backlight); bool backlight);
void setTexture(const std::string& name, void setTexture(const std::string& name,
const texture_names_map* varTextures); const texture_names_map* varTextures);
void setTexture(Texture* texture); void setTexture(const Texture* texture);
void flush(); void flush();
struct DrawEntry { struct DrawEntry {
@ -96,4 +97,6 @@ public:
const model::Model* model, const model::Model* model,
const texture_names_map* varTextures); const texture_names_map* varTextures);
void render(); void render();
void setLightsOffset(const glm::vec3& offset);
}; };

View 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();
}
}

View 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
);
};

View File

@ -58,11 +58,13 @@ Skybox::Skybox(uint size, Shader* shader)
Skybox::~Skybox() = default; Skybox::~Skybox() = default;
void Skybox::drawBackground(Camera* camera, Assets* assets, int width, int height) { void Skybox::drawBackground(
auto backShader = assets->get<Shader>("background"); const Camera& camera, const Assets& assets, int width, int height
) {
auto backShader = assets.get<Shader>("background");
backShader->use(); backShader->use();
backShader->uniformMatrix("u_view", camera->getView(false)); backShader->uniformMatrix("u_view", camera.getView(false));
backShader->uniform1f("u_zoom", camera->zoom*camera->getFov()/(M_PI*0.5f)); backShader->uniform1f("u_zoom", camera.zoom*camera.getFov()/(M_PI*0.5f));
backShader->uniform1f("u_ar", float(width)/float(height)); backShader->uniform1f("u_ar", float(width)/float(height));
backShader->uniform1i("u_cubemap", 1); backShader->uniform1i("u_cubemap", 1);
bind(); bind();
@ -93,8 +95,8 @@ void Skybox::drawStars(float angle, float opacity) {
void Skybox::draw( void Skybox::draw(
const DrawContext& pctx, const DrawContext& pctx,
Camera* camera, const Camera& camera,
Assets* assets, const Assets& assets,
float daytime, float daytime,
float fog) float fog)
{ {
@ -107,9 +109,9 @@ void Skybox::draw(
DrawContext ctx = pctx.sub(); DrawContext ctx = pctx.sub();
ctx.setBlendMode(BlendMode::addition); ctx.setBlendMode(BlendMode::addition);
auto p_shader = assets->get<Shader>("ui3d"); auto p_shader = assets.get<Shader>("ui3d");
p_shader->use(); 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)); p_shader->uniformMatrix("u_apply", glm::mat4(1.0f));
batch3d->begin(); batch3d->begin();
@ -117,7 +119,7 @@ void Skybox::draw(
float opacity = glm::pow(1.0f-fog, 7.0f); float opacity = glm::pow(1.0f-fog, 7.0f);
for (auto& sprite : sprites) { 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 sangle = daytime * float(M_PI)*2.0 + sprite.phase;
float distance = sprite.distance; float distance = sprite.distance;
@ -136,6 +138,7 @@ void Skybox::draw(
} }
void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality) { void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality) {
float dayTime = t;
DrawContext ctx = pctx.sub(); DrawContext ctx = pctx.sub();
ctx.setDepthMask(false); ctx.setDepthMask(false);
ctx.setDepthTest(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; t *= M_PI*2.0f;
lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f));
shader->uniform1i("u_quality", quality); shader->uniform1i("u_quality", quality);
shader->uniform1f("u_mie", mie); shader->uniform1f("u_mie", mie);
shader->uniform1f("u_fog", mie - 1.0f); 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++) { for (uint face = 0; face < 6; face++) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap->getId(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, cubemap->getId(), 0);
shader->uniform3f("u_xaxis", xaxs[face]); shader->uniform3f("u_xaxis", xaxs[face]);

View File

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include <glm/glm.hpp>
#include "typedefs.hpp" #include "typedefs.hpp"
#include "maths/fastmaths.hpp" #include "maths/fastmaths.hpp"
@ -27,21 +28,24 @@ class Skybox {
Shader* shader; Shader* shader;
bool ready = false; bool ready = false;
FastRandom random; FastRandom random;
glm::vec3 lightDir;
std::unique_ptr<Mesh> mesh; std::unique_ptr<Mesh> mesh;
std::unique_ptr<Batch3D> batch3d; std::unique_ptr<Batch3D> batch3d;
std::vector<skysprite> sprites; std::vector<skysprite> sprites;
void drawStars(float angle, float opacity); void drawStars(float angle, float opacity);
void drawBackground(Camera* camera, Assets* assets, int width, int height); void drawBackground(
const Camera& camera, const Assets& assets, int width, int height
);
public: public:
Skybox(uint size, Shader* shader); Skybox(uint size, Shader* shader);
~Skybox(); ~Skybox();
void draw( void draw(
const DrawContext& pctx, const DrawContext& pctx,
Camera* camera, const Camera& camera,
Assets* assets, const Assets& assets,
float daytime, float daytime,
float fog float fog
); );
@ -52,4 +56,8 @@ public:
bool isReady() const { bool isReady() const {
return ready; return ready;
} }
const glm::vec3 getLightDir() const {
return lightDir;
}
}; };

View File

@ -9,6 +9,7 @@
#include <memory> #include <memory>
#include "assets/Assets.hpp" #include "assets/Assets.hpp"
#include "assets/assets_util.hpp"
#include "content/Content.hpp" #include "content/Content.hpp"
#include "engine.hpp" #include "engine.hpp"
#include "frontend/LevelFrontend.hpp" #include "frontend/LevelFrontend.hpp"
@ -78,17 +79,17 @@ WorldRenderer::WorldRenderer(
WorldRenderer::~WorldRenderer() = default; WorldRenderer::~WorldRenderer() = default;
bool WorldRenderer::drawChunk( bool WorldRenderer::drawChunk(
size_t index, Camera* camera, Shader* shader, bool culling size_t index, const Camera& camera, Shader* shader, bool culling
) { ) {
auto chunk = level->chunks->getChunks()[index]; auto chunk = level->chunks->getChunks()[index];
if (!chunk->flags.lighted) { if (!chunk->flags.lighted) {
return false; return false;
} }
float distance = glm::distance( float distance = glm::distance(
camera->position, camera.position,
glm::vec3( glm::vec3(
(chunk->x + 0.5f) * CHUNK_W, (chunk->x + 0.5f) * CHUNK_W,
camera->position.y, camera.position.y,
(chunk->z + 0.5f) * CHUNK_D (chunk->z + 0.5f) * CHUNK_D
) )
); );
@ -113,7 +114,9 @@ bool WorldRenderer::drawChunk(
return true; return true;
} }
void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) { void WorldRenderer::drawChunks(
Chunks* chunks, const Camera& camera, Shader* shader
) {
auto assets = engine->getAssets(); auto assets = engine->getAssets();
auto atlas = assets->get<Atlas>("blocks"); auto atlas = assets->get<Atlas>("blocks");
@ -127,8 +130,8 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
if (chunks->getChunks()[i] == nullptr) continue; if (chunks->getChunks()[i] == nullptr) continue;
indices.emplace_back(i); indices.emplace_back(i);
} }
float px = camera->position.x / static_cast<float>(CHUNK_W) - 0.5f; float px = camera.position.x / static_cast<float>(CHUNK_W) - 0.5f;
float pz = camera->position.z / static_cast<float>(CHUNK_D) - 0.5f; float pz = camera.position.z / static_cast<float>(CHUNK_D) - 0.5f;
std::sort(indices.begin(), indices.end(), [chunks, px, pz](auto i, auto j) { std::sort(indices.begin(), indices.end(), [chunks, px, pz](auto i, auto j) {
const auto& chunksBuffer = chunks->getChunks(); const auto& chunksBuffer = chunks->getChunks();
const auto a = chunksBuffer[i].get(); const auto a = chunksBuffer[i].get();
@ -141,7 +144,7 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
}); });
bool culling = engine->getSettings().graphics.frustumCulling.get(); bool culling = engine->getSettings().graphics.frustumCulling.get();
if (culling) { if (culling) {
frustumCulling->update(camera->getProjView()); frustumCulling->update(camera.getProjView());
} }
chunks->visible = 0; chunks->visible = 0;
for (size_t i = 0; i < indices.size(); i++) { for (size_t i = 0; i < indices.size(); i++) {
@ -151,20 +154,21 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) {
void WorldRenderer::setupWorldShader( void WorldRenderer::setupWorldShader(
Shader* shader, Shader* shader,
Camera* camera, const Camera& camera,
const EngineSettings& settings, const EngineSettings& settings,
float fogFactor float fogFactor
) { ) {
shader->use(); shader->use();
shader->uniformMatrix("u_model", glm::mat4(1.0f)); shader->uniformMatrix("u_model", glm::mat4(1.0f));
shader->uniformMatrix("u_proj", camera->getProjection()); shader->uniformMatrix("u_proj", camera.getProjection());
shader->uniformMatrix("u_view", camera->getView()); shader->uniformMatrix("u_view", camera.getView());
shader->uniform1f("u_timer", timer); shader->uniform1f("u_timer", timer);
shader->uniform1f("u_gamma", settings.graphics.gamma.get()); shader->uniform1f("u_gamma", settings.graphics.gamma.get());
shader->uniform1f("u_fogFactor", fogFactor); shader->uniform1f("u_fogFactor", fogFactor);
shader->uniform1f("u_fogCurve", settings.graphics.fogCurve.get()); shader->uniform1f("u_fogCurve", settings.graphics.fogCurve.get());
shader->uniform1f("u_dayTime", level->getWorld()->getInfo().daytime); shader->uniform1f("u_dayTime", level->getWorld()->getInfo().daytime);
shader->uniform3f("u_cameraPos", camera->position); shader->uniform2f("u_lightDir", skybox->getLightDir());
shader->uniform3f("u_cameraPos", camera.position);
shader->uniform1i("u_cubemap", 1); shader->uniform1i("u_cubemap", 1);
auto indices = level->content->getIndices(); auto indices = level->content->getIndices();
@ -186,7 +190,7 @@ void WorldRenderer::setupWorldShader(
void WorldRenderer::renderLevel( void WorldRenderer::renderLevel(
const DrawContext&, const DrawContext&,
Camera* camera, const Camera& camera,
const EngineSettings& settings, const EngineSettings& settings,
float delta, float delta,
bool pause bool pause
@ -251,10 +255,10 @@ void WorldRenderer::renderBlockSelection() {
} }
void WorldRenderer::renderLines( void WorldRenderer::renderLines(
Camera* camera, Shader* linesShader, const DrawContext& pctx const Camera& camera, Shader* linesShader, const DrawContext& pctx
) { ) {
linesShader->use(); linesShader->use();
linesShader->uniformMatrix("u_projview", camera->getProjView()); linesShader->uniformMatrix("u_projview", camera.getProjView());
if (player->selection.vox.id != BLOCK_VOID) { if (player->selection.vox.id != BLOCK_VOID) {
renderBlockSelection(); renderBlockSelection();
} }
@ -268,7 +272,7 @@ void WorldRenderer::renderLines(
} }
void WorldRenderer::renderDebugLines( void WorldRenderer::renderDebugLines(
const DrawContext& pctx, Camera* camera, Shader* linesShader const DrawContext& pctx, const Camera& camera, Shader* linesShader
) { ) {
DrawContext ctx = pctx.sub(lineBatch.get()); DrawContext ctx = pctx.sub(lineBatch.get());
const auto& viewport = ctx.getViewport(); const auto& viewport = ctx.getViewport();
@ -280,8 +284,8 @@ void WorldRenderer::renderDebugLines(
linesShader->use(); linesShader->use();
if (showChunkBorders) { if (showChunkBorders) {
linesShader->uniformMatrix("u_projview", camera->getProjView()); linesShader->uniformMatrix("u_projview", camera.getProjView());
glm::vec3 coord = player->camera->position; glm::vec3 coord = player->fpCamera->position;
if (coord.x < 0) coord.x--; if (coord.x < 0) coord.x--;
if (coord.z < 0) coord.z--; if (coord.z < 0) coord.z--;
int cx = floordiv(static_cast<int>(coord.x), CHUNK_W); int cx = floordiv(static_cast<int>(coord.x), CHUNK_W);
@ -310,7 +314,7 @@ void WorldRenderer::renderDebugLines(
-length, -length,
length length
) * model * ) * model *
glm::inverse(camera->rotation) glm::inverse(camera.rotation)
); );
ctx.setDepthTest(false); ctx.setDepthTest(false);
@ -327,9 +331,70 @@ void WorldRenderer::renderDebugLines(
lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f); lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f);
} }
void WorldRenderer::renderHands(const Camera& camera, const Assets& assets) {
auto entityShader = assets.get<Shader>("entity");
auto indices = level->content->getIndices();
// get current chosen item
const auto& inventory = player->getInventory();
int slot = player->getChosenSlot();
const ItemStack& stack = inventory->getSlot(slot);
const auto& def = indices->items.require(stack.getItemId());
// prepare modified HUD camera
Camera hudcam = camera;
hudcam.far = 100.0f;
hudcam.setFov(1.2f);
hudcam.position = {};
// configure model matrix
const glm::vec3 itemOffset(0.08f, 0.035f, -0.1);
static glm::mat4 prevRotation(1.0f);
const float speed = 24.0f;
glm::mat4 matrix = glm::translate(glm::mat4(1.0f), itemOffset);
matrix = glm::scale(matrix, glm::vec3(0.1f));
glm::mat4 rotation = camera.rotation;
glm::quat rot0 = glm::quat_cast(prevRotation);
glm::quat rot1 = glm::quat_cast(rotation);
glm::quat finalRot =
glm::slerp(rot0, rot1, static_cast<float>(engine->getDelta() * speed));
rotation = glm::mat4_cast(finalRot);
matrix = rotation * matrix *
glm::rotate(
glm::mat4(1.0f), -glm::pi<float>() * 0.5f, glm::vec3(0, 1, 0)
);
prevRotation = rotation;
auto offset = -(camera.position - player->getPosition());
float angle = glm::radians(player->cam.x - 90);
float cos = glm::cos(angle);
float sin = glm::sin(angle);
float newX = offset.x * cos - offset.z * sin;
float newZ = offset.x * sin + offset.z * cos;
offset = glm::vec3(newX, offset.y, newZ);
matrix = matrix * glm::translate(glm::mat4(1.0f), offset);
// render
modelBatch->setLightsOffset(camera.position);
modelBatch->draw(
matrix,
glm::vec3(1.0f),
assets.get<model::Model>(def.modelName),
nullptr
);
Window::clearDepth();
setupWorldShader(entityShader, hudcam, engine->getSettings(), 0.0f);
skybox->bind();
modelBatch->render();
modelBatch->setLightsOffset(glm::vec3());
skybox->unbind();
}
void WorldRenderer::draw( void WorldRenderer::draw(
const DrawContext& pctx, const DrawContext& pctx,
Camera* camera, Camera& camera,
bool hudVisible, bool hudVisible,
bool pause, bool pause,
float delta, float delta,
@ -338,15 +403,15 @@ void WorldRenderer::draw(
timer += delta * !pause; timer += delta * !pause;
auto world = level->getWorld(); auto world = level->getWorld();
const Viewport& vp = pctx.getViewport(); const Viewport& vp = pctx.getViewport();
camera->aspect = vp.getWidth() / static_cast<float>(vp.getHeight()); camera.aspect = vp.getWidth() / static_cast<float>(vp.getHeight());
const auto& settings = engine->getSettings(); const auto& settings = engine->getSettings();
const auto& worldInfo = world->getInfo(); const auto& worldInfo = world->getInfo();
skybox->refresh(pctx, worldInfo.daytime, 1.0f + worldInfo.fog * 2.0f, 4); skybox->refresh(pctx, worldInfo.daytime, 1.0f + worldInfo.fog * 2.0f, 4);
auto assets = engine->getAssets(); const auto& assets = *engine->getAssets();
auto linesShader = assets->get<Shader>("lines"); auto linesShader = assets.get<Shader>("lines");
// World render scope with diegetic HUD included // World render scope with diegetic HUD included
{ {
@ -367,22 +432,70 @@ void WorldRenderer::draw(
// Debug lines // Debug lines
if (hudVisible) { if (hudVisible) {
renderLines(camera, linesShader, ctx); renderLines(camera, linesShader, ctx);
if (player->currentCamera == player->fpCamera) {
renderHands(camera, assets);
}
} }
} }
if (hudVisible && player->debug) { if (hudVisible && player->debug) {
renderDebugLines(wctx, camera, linesShader); renderDebugLines(wctx, camera, linesShader);
} }
renderBlockOverlay(wctx, assets);
} }
// Rendering fullscreen quad with // Rendering fullscreen quad with
auto screenShader = assets->get<Shader>("screen"); auto screenShader = assets.get<Shader>("screen");
screenShader->use(); screenShader->use();
screenShader->uniform1f("u_timer", timer); screenShader->uniform1f("u_timer", timer);
screenShader->uniform1f("u_dayTime", worldInfo.daytime); screenShader->uniform1f("u_dayTime", worldInfo.daytime);
postProcessing->render(pctx, screenShader); postProcessing->render(pctx, screenShader);
} }
void WorldRenderer::renderBlockOverlay(const DrawContext& wctx, const Assets& assets) {
int x = std::floor(player->currentCamera->position.x);
int y = std::floor(player->currentCamera->position.y);
int z = std::floor(player->currentCamera->position.z);
auto block = level->chunks->get(x, y, z);
if (block && block->id) {
const auto& def =
level->content->getIndices()->blocks.require(block->id);
if (def.overlayTexture.empty()) {
return;
}
auto textureRegion = util::get_texture_region(
assets, def.overlayTexture, "blocks:notfound"
);
DrawContext ctx = wctx.sub();
ctx.setDepthTest(false);
ctx.setCullFace(false);
auto& shader = assets.require<Shader>("ui3d");
shader.use();
batch3d->begin();
shader.uniformMatrix("u_projview", glm::mat4(1.0f));
shader.uniformMatrix("u_apply", glm::mat4(1.0f));
auto light = level->chunks->getLight(x, y, z);
float s = Lightmap::extract(light, 3) / 15.0f;
glm::vec4 tint(
glm::min(1.0f, Lightmap::extract(light, 0) / 15.0f + s),
glm::min(1.0f, Lightmap::extract(light, 1) / 15.0f + s),
glm::min(1.0f, Lightmap::extract(light, 2) / 15.0f + s),
1.0f
);
batch3d->texture(textureRegion.texture);
batch3d->sprite(
glm::vec3(),
glm::vec3(0, 1, 0),
glm::vec3(1, 0, 0),
2,
2,
textureRegion.region,
tint
);
batch3d->flush();
}
}
void WorldRenderer::drawBorders( void WorldRenderer::drawBorders(
int sx, int sy, int sz, int ex, int ey, int ez int sx, int sy, int sz, int ex, int ey, int ez
) { ) {

View File

@ -23,6 +23,7 @@ class Skybox;
class PostProcessing; class PostProcessing;
class DrawContext; class DrawContext;
class ModelBatch; class ModelBatch;
class Assets;
struct EngineSettings; struct EngineSettings;
namespace model { namespace model {
@ -41,16 +42,20 @@ class WorldRenderer {
std::unique_ptr<ModelBatch> modelBatch; std::unique_ptr<ModelBatch> modelBatch;
float timer = 0.0f; float timer = 0.0f;
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling); bool drawChunk(size_t index, const Camera& camera, Shader* shader, bool culling);
void drawChunks(Chunks* chunks, Camera* camera, Shader* shader); void drawChunks(Chunks* chunks, const Camera& camera, Shader* shader);
/// @brief Render block selection lines /// @brief Render block selection lines
void renderBlockSelection(); void renderBlockSelection();
void renderHands(const Camera& camera, const Assets& assets);
/// @brief Render lines (selection and debug) /// @brief Render lines (selection and debug)
/// @param camera active camera /// @param camera active camera
/// @param linesShader shader used /// @param linesShader shader used
void renderLines(Camera* camera, Shader* linesShader, const DrawContext& pctx); void renderLines(
const Camera& camera, Shader* linesShader, const DrawContext& pctx
);
/// @brief Render all debug lines (chunks borders, coord system guides) /// @brief Render all debug lines (chunks borders, coord system guides)
/// @param context graphics context /// @param context graphics context
@ -58,13 +63,15 @@ class WorldRenderer {
/// @param linesShader shader used /// @param linesShader shader used
void renderDebugLines( void renderDebugLines(
const DrawContext& context, const DrawContext& context,
Camera* camera, const Camera& camera,
Shader* linesShader Shader* linesShader
); );
void renderBlockOverlay(const DrawContext& context, const Assets& assets);
void setupWorldShader( void setupWorldShader(
Shader* shader, Shader* shader,
Camera* camera, const Camera& camera,
const EngineSettings& settings, const EngineSettings& settings,
float fogFactor float fogFactor
); );
@ -77,7 +84,7 @@ public:
void draw( void draw(
const DrawContext& context, const DrawContext& context,
Camera* camera, Camera& camera,
bool hudVisible, bool hudVisible,
bool pause, bool pause,
float delta, float delta,
@ -91,7 +98,7 @@ public:
/// @param settings engine settings /// @param settings engine settings
void renderLevel( void renderLevel(
const DrawContext& context, const DrawContext& context,
Camera* camera, const Camera& camera,
const EngineSettings& settings, const EngineSettings& settings,
float delta, float delta,
bool pause bool pause

View File

@ -1,6 +1,7 @@
#include "InventoryView.hpp" #include "InventoryView.hpp"
#include "assets/Assets.hpp" #include "assets/Assets.hpp"
#include "assets/assets_util.hpp"
#include "content/Content.hpp" #include "content/Content.hpp"
#include "frontend/LevelFrontend.hpp" #include "frontend/LevelFrontend.hpp"
#include "frontend/locale.hpp" #include "frontend/locale.hpp"
@ -161,9 +162,9 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) {
auto& item = indices->items.require(stack.getItemId()); auto& item = indices->items.require(stack.getItemId());
switch (item.iconType) { switch (item.iconType) {
case item_icon_type::none: case ItemIconType::NONE:
break; break;
case item_icon_type::block: { case ItemIconType::BLOCK: {
const Block& cblock = content->blocks.require(item.icon); const Block& cblock = content->blocks.require(item.icon);
batch->texture(previews->getTexture()); batch->texture(previews->getTexture());
@ -173,23 +174,14 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) {
0, 0, 0, region, false, true, tint); 0, 0, 0, region, false, true, tint);
break; break;
} }
case item_icon_type::sprite: { case ItemIconType::SPRITE: {
size_t index = item.icon.find(':'); auto textureRegion =
std::string name = item.icon.substr(index+1); util::get_texture_region(*assets, item.icon, "blocks:notfound");
UVRegion region(0.0f, 0.0, 1.0f, 1.0f);
if (index == std::string::npos) { batch->texture(textureRegion.texture);
batch->texture(assets->get<Texture>(name));
} else {
std::string atlasname = item.icon.substr(0, index);
auto atlas = assets->get<Atlas>(atlasname);
if (atlas && atlas->has(name)) {
region = atlas->get(name);
batch->texture(atlas->getTexture());
}
}
batch->rect( batch->rect(
pos.x, pos.y, slotSize, slotSize, pos.x, pos.y, slotSize, slotSize,
0, 0, 0, region, false, true, tint); 0, 0, 0, textureRegion.region, false, true, tint);
break; break;
} }
} }

View File

@ -14,4 +14,5 @@ void ItemDef::cloneTo(ItemDef& dst) {
dst.icon = icon; dst.icon = icon;
dst.placingBlock = placingBlock; dst.placingBlock = placingBlock;
dst.scriptName = scriptName; dst.scriptName = scriptName;
dst.modelName = modelName;
} }

View File

@ -12,10 +12,10 @@ struct item_funcs_set {
bool on_block_break_by : 1; bool on_block_break_by : 1;
}; };
enum class item_icon_type { enum class ItemIconType {
none, // invisible (core:empty) must not be rendered NONE, // invisible (core:empty) must not be rendered
sprite, // textured quad: icon is `atlas_name:texture_name` SPRITE, // textured quad: icon is `atlas_name:texture_name`
block, // block preview: icon is string block id BLOCK, // block preview: icon is string block id
}; };
struct ItemDef { struct ItemDef {
@ -29,12 +29,14 @@ struct ItemDef {
bool generated = false; bool generated = false;
uint8_t emission[4] {0, 0, 0, 0}; uint8_t emission[4] {0, 0, 0, 0};
item_icon_type iconType = item_icon_type::sprite; ItemIconType iconType = ItemIconType::SPRITE;
std::string icon = "blocks:notfound"; std::string icon = "blocks:notfound";
std::string placingBlock = "core:air"; std::string placingBlock = "core:air";
std::string scriptName = name.substr(name.find(':') + 1); std::string scriptName = name.substr(name.find(':') + 1);
std::string modelName = name + ".model";
struct { struct {
itemid_t id; itemid_t id;
blockid_t placingBlock; blockid_t placingBlock;

View File

@ -41,7 +41,7 @@ CameraControl::CameraControl(
const std::shared_ptr<Player>& player, const CameraSettings& settings const std::shared_ptr<Player>& player, const CameraSettings& settings
) )
: player(player), : player(player),
camera(player->camera), camera(player->fpCamera),
settings(settings), settings(settings),
offset(0.0f, 0.7f, 0.0f) { offset(0.0f, 0.7f, 0.0f) {
} }
@ -353,7 +353,7 @@ static void pick_block(
voxel* PlayerController::updateSelection(float maxDistance) { voxel* PlayerController::updateSelection(float maxDistance) {
auto indices = level->content->getIndices(); auto indices = level->content->getIndices();
auto chunks = level->chunks.get(); auto chunks = level->chunks.get();
auto camera = player->camera.get(); auto camera = player->fpCamera.get();
auto& selection = player->selection; auto& selection = player->selection;
glm::vec3 end; glm::vec3 end;
@ -416,7 +416,7 @@ voxel* PlayerController::updateSelection(float maxDistance) {
void PlayerController::processRightClick(const Block& def, const Block& target) { void PlayerController::processRightClick(const Block& def, const Block& target) {
const auto& selection = player->selection; const auto& selection = player->selection;
auto chunks = level->chunks.get(); auto chunks = level->chunks.get();
auto camera = player->camera.get(); auto camera = player->fpCamera.get();
blockstate state {}; blockstate state {};
state.rotation = determine_rotation(&def, selection.normal, camera->dir); state.rotation = determine_rotation(&def, selection.normal, camera->dir);

View File

@ -10,55 +10,71 @@ static const ItemDef* get_item_def(lua::State* L, int idx) {
return indices->items.get(id); return indices->items.get(id);
} }
static int l_item_name(lua::State* L) { static int l_name(lua::State* L) {
if (auto def = get_item_def(L, 1)) { if (auto def = get_item_def(L, 1)) {
return lua::pushstring(L, def->name); return lua::pushstring(L, def->name);
} }
return 0; return 0;
} }
static int l_item_index(lua::State* L) { static int l_index(lua::State* L) {
auto name = lua::require_string(L, 1); auto name = lua::require_string(L, 1);
return lua::pushinteger(L, content->items.require(name).rt.id); return lua::pushinteger(L, content->items.require(name).rt.id);
} }
static int l_item_stack_size(lua::State* L) { static int l_stack_size(lua::State* L) {
if (auto def = get_item_def(L, 1)) { if (auto def = get_item_def(L, 1)) {
return lua::pushinteger(L, def->stackSize); return lua::pushinteger(L, def->stackSize);
} }
return 0; return 0;
} }
static int l_item_defs_count(lua::State* L) { static int l_defs_count(lua::State* L) {
return lua::pushinteger(L, indices->items.count()); return lua::pushinteger(L, indices->items.count());
} }
static int l_item_get_icon(lua::State* L) { static int l_get_icon(lua::State* L) {
if (auto def = get_item_def(L, 1)) { if (auto def = get_item_def(L, 1)) {
switch (def->iconType) { switch (def->iconType) {
case item_icon_type::none: case ItemIconType::NONE:
return 0; return 0;
case item_icon_type::sprite: case ItemIconType::SPRITE:
return lua::pushstring(L, def->icon); return lua::pushstring(L, def->icon);
case item_icon_type::block: case ItemIconType::BLOCK:
return lua::pushstring(L, "block-previews:" + def->icon); return lua::pushstring(L, "block-previews:" + def->icon);
} }
} }
return 0; return 0;
} }
static int l_item_caption(lua::State* L) { static int l_caption(lua::State* L) {
if (auto def = get_item_def(L, 1)) { if (auto def = get_item_def(L, 1)) {
return lua::pushstring(L, def->caption); return lua::pushstring(L, def->caption);
} }
return 0; return 0;
} }
static int l_placing_block(lua::State* L) {
if (auto def = get_item_def(L, 1)) {
return lua::pushinteger(L, def->rt.placingBlock);
}
return 0;
}
static int l_model_name(lua::State* L) {
if (auto def = get_item_def(L, 1)) {
return lua::pushstring(L, def->modelName);
}
return 0;
}
const luaL_Reg itemlib[] = { const luaL_Reg itemlib[] = {
{"index", lua::wrap<l_item_index>}, {"index", lua::wrap<l_index>},
{"name", lua::wrap<l_item_name>}, {"name", lua::wrap<l_name>},
{"stack_size", lua::wrap<l_item_stack_size>}, {"stack_size", lua::wrap<l_stack_size>},
{"defs_count", lua::wrap<l_item_defs_count>}, {"defs_count", lua::wrap<l_defs_count>},
{"icon", lua::wrap<l_item_get_icon>}, {"icon", lua::wrap<l_get_icon>},
{"caption", lua::wrap<l_item_caption>}, {"caption", lua::wrap<l_caption>},
{"placing_block", lua::wrap<l_placing_block>},
{"model_name", lua::wrap<l_model_name>},
{NULL, NULL}}; {NULL, NULL}};

View File

@ -85,7 +85,7 @@ static int l_set_rot(lua::State* L) {
static int l_get_dir(lua::State* L) { static int l_get_dir(lua::State* L) {
if (auto player = get_player(L, 1)) { if (auto player = get_player(L, 1)) {
return lua::pushvec3(L, player->camera->front); return lua::pushvec3(L, player->fpCamera->front);
} }
return 0; return 0;
} }

View File

@ -40,11 +40,11 @@ Player::Player(
position(position), position(position),
inventory(std::move(inv)), inventory(std::move(inv)),
eid(eid), eid(eid),
camera(level->getCamera("core:first-person")), fpCamera(level->getCamera("core:first-person")),
spCamera(level->getCamera("core:third-person-front")), spCamera(level->getCamera("core:third-person-front")),
tpCamera(level->getCamera("core:third-person-back")), tpCamera(level->getCamera("core:third-person-back")),
currentCamera(camera) { currentCamera(fpCamera) {
camera->setFov(glm::radians(90.0f)); fpCamera->setFov(glm::radians(90.0f));
spCamera->setFov(glm::radians(90.0f)); spCamera->setFov(glm::radians(90.0f));
tpCamera->setFov(glm::radians(90.0f)); tpCamera->setFov(glm::radians(90.0f));
} }
@ -93,16 +93,16 @@ void Player::updateInput(PlayerInput& input, float delta) {
glm::vec3 dir(0, 0, 0); glm::vec3 dir(0, 0, 0);
if (input.moveForward) { if (input.moveForward) {
dir += camera->dir; dir += fpCamera->dir;
} }
if (input.moveBack) { if (input.moveBack) {
dir -= camera->dir; dir -= fpCamera->dir;
} }
if (input.moveRight) { if (input.moveRight) {
dir += camera->right; dir += fpCamera->right;
} }
if (input.moveLeft) { if (input.moveLeft) {
dir -= camera->right; dir -= fpCamera->right;
} }
if (glm::length(dir) > 0.0f) { if (glm::length(dir) > 0.0f) {
dir = glm::normalize(dir); dir = glm::normalize(dir);
@ -166,7 +166,7 @@ void Player::postUpdate() {
auto& skeleton = entity->getSkeleton(); auto& skeleton = entity->getSkeleton();
skeleton.visible = currentCamera != camera; skeleton.visible = currentCamera != fpCamera;
auto body = skeleton.config->find("body"); auto body = skeleton.config->find("body");
auto head = skeleton.config->find("head"); auto head = skeleton.config->find("head");
@ -252,7 +252,7 @@ entityid_t Player::getSelectedEntity() const {
return selectedEid; return selectedEid;
} }
std::shared_ptr<Inventory> Player::getInventory() const { const std::shared_ptr<Inventory>& Player::getInventory() const {
return inventory; return inventory;
} }
@ -289,7 +289,7 @@ void Player::deserialize(const dv::value& src) {
const auto& posarr = src["position"]; const auto& posarr = src["position"];
dv::get_vec(posarr, position); dv::get_vec(posarr, position);
camera->position = position; fpCamera->position = position;
const auto& rotarr = src["rotation"]; const auto& rotarr = src["rotation"];
dv::get_vec(rotarr, cam); dv::get_vec(rotarr, cam);

View File

@ -52,7 +52,7 @@ class Player : public Object, public Serializable {
entityid_t eid; entityid_t eid;
entityid_t selectedEid; entityid_t selectedEid;
public: public:
std::shared_ptr<Camera> camera, spCamera, tpCamera; std::shared_ptr<Camera> fpCamera, spCamera, tpCamera;
std::shared_ptr<Camera> currentCamera; std::shared_ptr<Camera> currentCamera;
bool debug = false; bool debug = false;
glm::vec3 cam {}; glm::vec3 cam {};
@ -91,7 +91,7 @@ public:
entityid_t getSelectedEntity() const; entityid_t getSelectedEntity() const;
std::shared_ptr<Inventory> getInventory() const; const std::shared_ptr<Inventory>& getInventory() const;
glm::vec3 getPosition() const { glm::vec3 getPosition() const {
return position; return position;

View File

@ -141,6 +141,7 @@ void Block::cloneTo(Block& dst) {
dst.uiLayout = uiLayout; dst.uiLayout = uiLayout;
dst.inventorySize = inventorySize; dst.inventorySize = inventorySize;
dst.tickInterval = tickInterval; dst.tickInterval = tickInterval;
dst.overlayTexture = overlayTexture;
} }
static std::set<std::string, std::less<>> RESERVED_BLOCK_FIELDS { static std::set<std::string, std::less<>> RESERVED_BLOCK_FIELDS {

View File

@ -4,6 +4,7 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <array>
#include "maths/UVRegion.hpp" #include "maths/UVRegion.hpp"
#include "maths/aabb.hpp" #include "maths/aabb.hpp"
@ -111,7 +112,7 @@ public:
std::string caption; std::string caption;
/// @brief Textures set applied to block sides /// @brief Textures set applied to block sides
std::string textureFaces[6]; // -x,x, -y,y, -z,z std::array<std::string, 6> textureFaces; // -x,x, -y,y, -z,z
std::vector<std::string> modelTextures = {}; std::vector<std::string> modelTextures = {};
std::vector<BoxModel> modelBoxes = {}; std::vector<BoxModel> modelBoxes = {};
@ -184,6 +185,9 @@ public:
/// @brief Block will be used instead of this if generated on surface /// @brief Block will be used instead of this if generated on surface
std::string surfaceReplacement = name; std::string surfaceReplacement = name;
/// @brief Texture will be shown on screen if camera is inside of the block
std::string overlayTexture;
/// @brief Default block layout will be used by hud.open_block(...) /// @brief Default block layout will be used by hud.open_block(...)
std::string uiLayout = name; std::string uiLayout = name;

View File

@ -29,21 +29,21 @@ void Camera::rotate(float x, float y, float z) {
updateVectors(); updateVectors();
} }
glm::mat4 Camera::getProjection() { glm::mat4 Camera::getProjection() const {
constexpr float epsilon = 1e-6f; // 0.000001 constexpr float epsilon = 1e-6f; // 0.000001
float aspect_ratio = this->aspect; float aspect_ratio = this->aspect;
if (std::fabs(aspect_ratio) < epsilon) { if (std::fabs(aspect_ratio) < epsilon) {
aspect_ratio = (float)Window::width / (float)Window::height; aspect_ratio = (float)Window::width / (float)Window::height;
} }
if (perspective) if (perspective)
return glm::perspective(fov * zoom, aspect_ratio, 0.05f, 1500.0f); return glm::perspective(fov * zoom, aspect_ratio, near, far);
else if (flipped) else if (flipped)
return glm::ortho(0.0f, fov * aspect_ratio, fov, 0.0f); return glm::ortho(0.0f, fov * aspect_ratio, fov, 0.0f);
else else
return glm::ortho(0.0f, fov * aspect_ratio, 0.0f, fov); return glm::ortho(0.0f, fov * aspect_ratio, 0.0f, fov);
} }
glm::mat4 Camera::getView(bool pos) { glm::mat4 Camera::getView(bool pos) const {
glm::vec3 camera_pos = this->position; glm::vec3 camera_pos = this->position;
if (!pos) { if (!pos) {
camera_pos = glm::vec3(0.0f); camera_pos = glm::vec3(0.0f);
@ -55,7 +55,7 @@ glm::mat4 Camera::getView(bool pos) {
} }
} }
glm::mat4 Camera::getProjView(bool pos) { glm::mat4 Camera::getProjView(bool pos) const {
return getProjection() * getView(pos); return getProjection() * getView(pos);
} }

View File

@ -18,6 +18,8 @@ public:
bool perspective = true; bool perspective = true;
bool flipped = false; bool flipped = false;
float aspect = 0.0f; float aspect = 0.0f;
float near = 0.05f;
float far = 1500.0f;
Camera() { Camera() {
updateVectors(); updateVectors();
@ -27,9 +29,9 @@ public:
void updateVectors(); void updateVectors();
void rotate(float x, float y, float z); void rotate(float x, float y, float z);
glm::mat4 getProjection(); glm::mat4 getProjection() const;
glm::mat4 getView(bool position = true); glm::mat4 getView(bool position = true) const;
glm::mat4 getProjView(bool position = true); glm::mat4 getProjView(bool position = true) const;
void setFov(float fov); void setFov(float fov);
float getFov() const; float getFov() const;

View File

@ -5,7 +5,7 @@
TEST(VEC3, Decode) { TEST(VEC3, Decode) {
auto file = std::filesystem::u8path( auto file = std::filesystem::u8path(
"../res/content/base/models/demo.vec3" "../res/models/block.vec3"
); );
auto bytes = files::read_bytes_buffer(file); auto bytes = files::read_bytes_buffer(file);
auto model = vec3::load(file.u8string(), bytes); auto model = vec3::load(file.u8string(), bytes);