1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2

This commit is contained in:
Gefüllte Taubenbrust 2025-01-14 20:31:26 +01:00
commit 6b1785eb2c
128 changed files with 1273 additions and 1076 deletions

26
.github/workflows/png_file_checks.yml vendored Normal file
View file

@ -0,0 +1,26 @@
name: png_file_checks
# Check whether all png files are in a valid format
on:
push:
paths:
- '**.png'
- '.github/workflows/**.yml'
pull_request:
paths:
- '**.png'
- '.github/workflows/**.yml'
jobs:
png_optimized:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
sudo apt-get update
sudo apt install -y optipng
- name: Check whether all png files are optimized
run: |
./util/ci/check_png_optimized.sh

View file

@ -14,6 +14,9 @@ https://www.apache.org/licenses/LICENSE-2.0.html
Textures by Zughy are under CC BY-SA 4.0 Textures by Zughy are under CC BY-SA 4.0
https://creativecommons.org/licenses/by-sa/4.0/ https://creativecommons.org/licenses/by-sa/4.0/
Textures by cx384 are under CC BY-SA 4.0
https://creativecommons.org/licenses/by-sa/4.0/
Media files by DS are under CC BY-SA 4.0 Media files by DS are under CC BY-SA 4.0
https://creativecommons.org/licenses/by-sa/4.0/ https://creativecommons.org/licenses/by-sa/4.0/
@ -64,7 +67,13 @@ Zughy:
textures/base/pack/settings_info.png textures/base/pack/settings_info.png
textures/base/pack/settings_reset.png textures/base/pack/settings_reset.png
textures/base/pack/server_url.png textures/base/pack/server_url.png
textures/base/pack/server_url_unavailable.png
textures/base/pack/server_view_clients.png textures/base/pack/server_view_clients.png
textures/base/pack/server_view_clients_unavailable.png
cx384:
textures/base/pack/server_view_mods.png
textures/base/pack/server_view_mods_unavailable.png
appgurueu: appgurueu:
textures/base/pack/server_incompatible.png textures/base/pack/server_incompatible.png

View file

@ -308,23 +308,26 @@ core.register_entity(":__builtin:falling_node", {
core.remove_node(bcp) core.remove_node(bcp)
else else
-- We are placing on top so check what's there
np.y = np.y + 1 np.y = np.y + 1
end
-- Check what's here local n2 = core.get_node(np)
local n2 = core.get_node(np) local nd = core.registered_nodes[n2.name]
local nd = core.registered_nodes[n2.name] if not nd or nd.buildable_to then
-- If it's not air or liquid, remove node and replace it with core.remove_node(np)
-- it's drops else
if n2.name ~= "air" and (not nd or nd.liquidtype ~= "source") then -- 'walkable' is used to mean "falling nodes can't replace this"
if nd and nd.buildable_to == false then -- here. Normally we would collide with the walkable node itself
-- and place our node on top (so `n2.name == "air"`), but we
-- re-check this in case we ended up inside a node.
if not nd.diggable or nd.walkable then
return false
end
nd.on_dig(np, n2, nil) nd.on_dig(np, n2, nil)
-- If it's still there, it might be protected -- If it's still there, it might be protected
if core.get_node(np).name == n2.name then if core.get_node(np).name == n2.name then
return false return false
end end
else
core.remove_node(np)
end end
end end

View file

@ -0,0 +1,105 @@
-- Luanti
-- Copyright (C) 2024 cx384
-- SPDX-License-Identifier: LGPL-2.1-or-later
local function get_formspec(dialogdata)
local TOUCH_GUI = core.settings:get_bool("touch_gui")
local server = dialogdata.server
local group_by_prefix = dialogdata.group_by_prefix
local expand_all = dialogdata.expand_all
-- A wrongly behaving server may send ill formed mod names
table.sort(server.mods)
local cells = {}
if group_by_prefix then
local function get_prefix(mod)
return mod:match("[^_]*")
end
local count = {}
for _, mod in ipairs(server.mods) do
local prefix = get_prefix(mod)
count[prefix] = (count[prefix] or 0) + 1
end
local last_prefix
local function add_row(depth, mod)
table.insert(cells, ("%d"):format(depth))
table.insert(cells, mod)
end
for i, mod in ipairs(server.mods) do
local prefix = get_prefix(mod)
if last_prefix == prefix then
add_row(1, mod)
elseif count[prefix] > 1 then
add_row(0, prefix)
add_row(1, mod)
else
add_row(0, mod)
end
last_prefix = prefix
end
else
cells = table.copy(server.mods)
end
for i, cell in ipairs(cells) do
cells[i] = core.formspec_escape(cell)
end
cells = table.concat(cells, ",")
local heading
if server.gameid then
heading = fgettext("The $1 server uses a game called $2 and the following mods:",
"<b>" .. core.hypertext_escape(server.name) .. "</b>",
"<style font=mono>" .. core.hypertext_escape(server.gameid) .. "</style>")
else
heading = fgettext("The $1 server uses the following mods:",
"<b>" .. core.hypertext_escape(server.name) .. "</b>")
end
local formspec = {
"formspec_version[8]",
"size[8,9.5]",
TOUCH_GUI and "padding[0.01,0.01]" or "",
"hypertext[0,0;8,1.5;;<global margin=5 halign=center valign=middle>", heading, "]",
"tablecolumns[", group_by_prefix and
(expand_all and "indent;text" or "tree;text") or "text", "]",
"table[0.5,1.5;7,6.8;mods;", cells, "]",
"checkbox[0.5,8.7;group_by_prefix;", fgettext("Group by prefix"), ";",
group_by_prefix and "true" or "false", "]",
group_by_prefix and ("checkbox[0.5,9.15;expand_all;" .. fgettext("Expand all") .. ";" ..
(expand_all and "true" or "false") .. "]") or "",
"button[5.5,8.5;2,0.8;quit;OK]"
}
return table.concat(formspec, "")
end
local function buttonhandler(this, fields)
if fields.quit then
this:delete()
return true
end
if fields.group_by_prefix then
this.data.group_by_prefix = core.is_yes(fields.group_by_prefix)
return true
end
if fields.expand_all then
this.data.expand_all = core.is_yes(fields.expand_all)
return true
end
return false
end
function create_server_list_mods_dialog(server)
local retval = dialog_create("dlg_server_list_mods",
get_formspec,
buttonhandler,
nil)
retval.data.group_by_prefix = false
retval.data.expand_all = false
retval.data.server = server
return retval
end

View file

@ -56,6 +56,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua") dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua") dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua")
dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua") dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua")
dofile(menupath .. DIR_DELIM .. "dlg_server_list_mods.lua")
local tabs = { local tabs = {
content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"), content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"),

View file

@ -161,6 +161,26 @@ local function get_formspec(tabview, name, tabdata)
core.formspec_escape(gamedata.serverdescription) .. "]" core.formspec_escape(gamedata.serverdescription) .. "]"
end end
-- Mods button
local mods = selected_server.mods
if mods and #mods > 0 then
local tooltip = ""
if selected_server.gameid then
tooltip = fgettext("Game: $1", selected_server.gameid) .. "\n"
end
tooltip = tooltip .. fgettext("Number of mods: $1", #mods)
retval = retval ..
"tooltip[btn_view_mods;" .. tooltip .. "]" ..
"style[btn_view_mods;padding=6]" ..
"image_button[4,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
"server_view_mods.png") .. ";btn_view_mods;]"
else
retval = retval .. "image[4.1,1.4;0.3,0.3;" .. core.formspec_escape(defaulttexturedir ..
"server_view_mods_unavailable.png") .. "]"
end
-- Clients list button
local clients_list = selected_server.clients_list local clients_list = selected_server.clients_list
local can_view_clients_list = clients_list and #clients_list > 0 local can_view_clients_list = clients_list and #clients_list > 0
if can_view_clients_list then if can_view_clients_list then
@ -178,15 +198,23 @@ local function get_formspec(tabview, name, tabdata)
retval = retval .. "style[btn_view_clients;padding=6]" retval = retval .. "style[btn_view_clients;padding=6]"
retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
"server_view_clients.png") .. ";btn_view_clients;]" "server_view_clients.png") .. ";btn_view_clients;]"
else
retval = retval .. "image[4.6,1.4;0.3,0.3;" .. core.formspec_escape(defaulttexturedir ..
"server_view_clients_unavailable.png") .. "]"
end end
-- URL button
if selected_server.url then if selected_server.url then
retval = retval .. "tooltip[btn_server_url;" .. fgettext("Open server website") .. "]" retval = retval .. "tooltip[btn_server_url;" .. fgettext("Open server website") .. "]"
retval = retval .. "style[btn_server_url;padding=6]" retval = retval .. "style[btn_server_url;padding=6]"
retval = retval .. "image_button[" .. (can_view_clients_list and "4" or "4.5") .. ",1.3;0.5,0.5;" .. retval = retval .. "image_button[3.5,1.3;0.5,0.5;" ..
core.formspec_escape(defaulttexturedir .. "server_url.png") .. ";btn_server_url;]" core.formspec_escape(defaulttexturedir .. "server_url.png") .. ";btn_server_url;]"
else
retval = retval .. "image[3.6,1.4;0.3,0.3;" .. core.formspec_escape(defaulttexturedir ..
"server_url_unavailable.png") .. "]"
end end
-- Favorites toggle button
if is_selected_fav() then if is_selected_fav() then
retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]" retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
retval = retval .. "style[btn_delete_favorite;padding=6]" retval = retval .. "style[btn_delete_favorite;padding=6]"
@ -468,6 +496,14 @@ local function main_button_handler(tabview, fields, name, tabdata)
return true return true
end end
if fields.btn_view_mods then
local dlg = create_server_list_mods_dialog(find_selected_server())
dlg:set_parent(tabview)
tabview:hide()
dlg:show()
return true
end
if fields.btn_mp_clear then if fields.btn_mp_clear then
tabdata.search_for = "" tabdata.search_for = ""
menudata.search_result = nil menudata.search_result = nil

View file

@ -377,17 +377,12 @@ fog_start (Fog start) float 0.4 0.0 0.99
[**Clouds] [**Clouds]
# Clouds are a client-side effect. # Allow clouds to look 3D instead of flat.
enable_clouds (Clouds) bool true
# Use 3D cloud look instead of flat.
#
# Requires: enable_clouds
enable_3d_clouds (3D clouds) bool true enable_3d_clouds (3D clouds) bool true
# Use smooth cloud shading. # Use smooth cloud shading.
# #
# Requires: enable_3d_clouds, enable_clouds # Requires: enable_3d_clouds
soft_clouds (Soft clouds) bool false soft_clouds (Soft clouds) bool false
[**Filtering and Antialiasing] [**Filtering and Antialiasing]
@ -472,9 +467,6 @@ smooth_lighting (Smooth lighting) bool true
# at the expense of minor visual glitches that do not impact game playability. # at the expense of minor visual glitches that do not impact game playability.
performance_tradeoffs (Tradeoffs for performance) bool false performance_tradeoffs (Tradeoffs for performance) bool false
# Adds particles when digging a node.
enable_particles (Digging particles) bool true
[**Waving Nodes] [**Waving Nodes]
@ -667,8 +659,7 @@ sound_volume (Volume) float 0.8 0.0 1.0
# Volume multiplier when the window is unfocused. # Volume multiplier when the window is unfocused.
sound_volume_unfocused (Volume when unfocused) float 0.3 0.0 1.0 sound_volume_unfocused (Volume when unfocused) float 0.3 0.0 1.0
# Whether to mute sounds. You can unmute sounds at any time, unless the # Whether to mute sounds. You can unmute sounds at any time.
# sound system is disabled (enable_sound=false).
# In-game, you can toggle the mute state with the mute key or by using the # In-game, you can toggle the mute state with the mute key or by using the
# pause menu. # pause menu.
mute_sound (Mute sound) bool false mute_sound (Mute sound) bool false
@ -709,12 +700,6 @@ formspec_fullscreen_bg_color (Formspec Full-Screen Background Color) string (0,0
# to hardware (e.g. render-to-texture for nodes in inventory). # to hardware (e.g. render-to-texture for nodes in inventory).
gui_scaling_filter (GUI scaling filter) bool false gui_scaling_filter (GUI scaling filter) bool false
# When gui_scaling_filter_txr2img is true, copy those images
# from hardware to software for scaling. When false, fall back
# to the old scaling method, for video drivers that don't
# properly support downloading textures back from hardware.
gui_scaling_filter_txr2img (GUI scaling filter txr2img) bool true
# Delay showing tooltips, stated in milliseconds. # Delay showing tooltips, stated in milliseconds.
tooltip_show_delay (Tooltip delay) int 400 0 18446744073709551615 tooltip_show_delay (Tooltip delay) int 400 0 18446744073709551615
@ -1869,10 +1854,7 @@ transparency_sorting_group_by_buffers (Transparency Sorting Group by Buffers) bo
# Radius of cloud area stated in number of 64 node cloud squares. # Radius of cloud area stated in number of 64 node cloud squares.
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners. # Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
cloud_radius (Cloud radius) int 12 1 62 cloud_radius (Cloud radius) int 12 8 62
# Whether node texture animations should be desynchronized per mapblock.
desynchronize_mapblock_texture_animation (Desynchronize block animation) bool false
# Delay between mesh updates on the client in ms. Increasing this will slow # Delay between mesh updates on the client in ms. Increasing this will slow
# down the rate of mesh updates, thus reducing jitter on slower clients. # down the rate of mesh updates, thus reducing jitter on slower clients.
@ -1942,7 +1924,7 @@ shadow_poisson_filter (Poisson filtering) bool true
# Minimum value: 1; maximum value: 16 # Minimum value: 1; maximum value: 16
# #
# Requires: enable_dynamic_shadows, opengl # Requires: enable_dynamic_shadows, opengl
shadow_update_frames (Map shadows update frames) int 8 1 16 shadow_update_frames (Map shadows update frames) int 16 1 32
# Set to true to render debugging breakdown of the bloom effect. # Set to true to render debugging breakdown of the bloom effect.
# In debug mode, the screen is split into 4 quadrants: # In debug mode, the screen is split into 4 quadrants:
@ -2126,9 +2108,6 @@ max_block_send_distance (Max block send distance) int 12 1 65535
# Set this to -1 to disable the limit. # Set this to -1 to disable the limit.
max_forceloaded_blocks (Maximum forceloaded blocks) int 16 -1 max_forceloaded_blocks (Maximum forceloaded blocks) int 16 -1
# Interval of sending time of day to clients, stated in seconds.
time_send_interval (Time send interval) float 5.0 0.001
# Interval of saving important changes in the world, stated in seconds. # Interval of saving important changes in the world, stated in seconds.
server_map_save_interval (Map save interval) float 5.3 0.001 server_map_save_interval (Map save interval) float 5.3 0.001
@ -2137,7 +2116,7 @@ server_map_save_interval (Map save interval) float 5.3 0.001
server_unload_unused_data_timeout (Unload unused server data) int 29 0 4294967295 server_unload_unused_data_timeout (Unload unused server data) int 29 0 4294967295
# Maximum number of statically stored objects in a block. # Maximum number of statically stored objects in a block.
max_objects_per_block (Maximum objects per block) int 256 1 65535 max_objects_per_block (Maximum objects per block) int 256 256 65535
# Length of time between active block management cycles, stated in seconds. # Length of time between active block management cycles, stated in seconds.
active_block_mgmt_interval (Active block management interval) float 2.0 0.0 active_block_mgmt_interval (Active block management interval) float 2.0 0.0
@ -2356,12 +2335,6 @@ show_technical_names (Show technical names) bool false
# Controlled by a checkbox in the settings menu. # Controlled by a checkbox in the settings menu.
show_advanced (Show advanced settings) bool false show_advanced (Show advanced settings) bool false
# Enables the sound system.
# If disabled, this completely disables all sounds everywhere and the in-game
# sound controls will be non-functional.
# Changing this setting requires a restart.
enable_sound (Sound) bool true
# Key for moving the player forward. # Key for moving the player forward.
keymap_forward (Forward key) key KEY_KEY_W keymap_forward (Forward key) key KEY_KEY_W

View file

@ -53,7 +53,6 @@ centroid varying float nightRatio;
varying highp vec3 eyeVec; varying highp vec3 eyeVec;
varying float nightFactor; varying float nightFactor;
#ifdef ENABLE_DYNAMIC_SHADOWS
#if (MATERIAL_WAVING_LIQUID && defined(ENABLE_WATER_REFLECTIONS)) #if (MATERIAL_WAVING_LIQUID && defined(ENABLE_WATER_REFLECTIONS))
vec4 perm(vec4 x) vec4 perm(vec4 x)
{ {
@ -536,7 +535,7 @@ void main(void)
col.rgb += water_reflect_color * f_shadow_factor * brightness_factor; col.rgb += water_reflect_color * f_shadow_factor * brightness_factor;
#endif #endif
#if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WAVING_LIQUID) #if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WATER_REFLECTIONS)
// Apply specular to blocks. // Apply specular to blocks.
if (dot(v_LightDirection, vNormal) < 0.0) { if (dot(v_LightDirection, vNormal) < 0.0) {
// This intensity is a placeholder and should be replaced by proper specular maps. // This intensity is a placeholder and should be replaced by proper specular maps.

View file

@ -5044,7 +5044,7 @@ inside the VoxelManip.
can use `core.emerge_area` to make sure that the area you want to can use `core.emerge_area` to make sure that the area you want to
read/write is already generated. read/write is already generated.
* Other mods, or the core itself, could possibly modify the area of the map * Other mods, or the engine itself, could possibly modify the area of the map
currently loaded into a VoxelManip object. With the exception of Mapgen currently loaded into a VoxelManip object. With the exception of Mapgen
VoxelManips (see above section), the internal buffers are not updated. For VoxelManips (see above section), the internal buffers are not updated. For
this reason, it is strongly encouraged to complete the usage of a particular this reason, it is strongly encouraged to complete the usage of a particular
@ -5059,9 +5059,11 @@ inside the VoxelManip.
Methods Methods
------- -------
* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object * `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object
containing the region formed by `p1` and `p2`. containing the region formed by `p1` and `p2`.
* returns actual emerged `pmin`, actual emerged `pmax` * returns actual emerged `pmin`, actual emerged `pmax`
* Note that calling this multiple times will *add* to the area loaded in the
VoxelManip, and not reset it.
* `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to * `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to
the map. the map.
* **important**: data must be set using `VoxelManip:set_data()` before * **important**: data must be set using `VoxelManip:set_data()` before
@ -5120,8 +5122,8 @@ Methods
generated mapchunk above are propagated down into the mapchunk, defaults generated mapchunk above are propagated down into the mapchunk, defaults
to `true` if left out. to `true` if left out.
* `update_liquids()`: Update liquid flow * `update_liquids()`: Update liquid flow
* `was_modified()`: Returns `true` if the data in the voxel manipulator has been modified * `was_modified()`: Returns `true` if the data in the VoxelManip has been modified
since it was last read from the map. This means you have to call `get_data` again. since it was last read from the map. This means you have to call `get_data()` again.
This only applies to a `VoxelManip` object from `core.get_mapgen_object`, This only applies to a `VoxelManip` object from `core.get_mapgen_object`,
where the engine will keep the map and the VM in sync automatically. where the engine will keep the map and the VM in sync automatically.
* Note: this doesn't do what you think it does and is subject to removal. Don't use it! * Note: this doesn't do what you think it does and is subject to removal. Don't use it!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

After

Width:  |  Height:  |  Size: 134 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 134 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 144 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 132 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 B

After

Width:  |  Height:  |  Size: 121 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 115 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

After

Width:  |  Height:  |  Size: 124 B

Before After
Before After

View file

@ -12,6 +12,7 @@ unittests.list = {}
-- player = false, -- Does test require a player? -- player = false, -- Does test require a player?
-- map = false, -- Does test require map access? -- map = false, -- Does test require map access?
-- async = false, -- Does the test run asynchronously? (read notes above!) -- async = false, -- Does the test run asynchronously? (read notes above!)
-- random = false, -- Does the test use math.random directly or indirectly?
-- } -- }
function unittests.register(name, func, opts) function unittests.register(name, func, opts)
local def = table.copy(opts or {}) local def = table.copy(opts or {})
@ -47,8 +48,18 @@ local function await(invoke)
return coroutine.yield() return coroutine.yield()
end end
local function printf(fmt, ...)
print(fmt:format(...))
end
function unittests.run_one(idx, counters, out_callback, player, pos) function unittests.run_one(idx, counters, out_callback, player, pos)
local def = unittests.list[idx] local def = unittests.list[idx]
local seed
if def.random then
seed = core.get_us_time()
math.randomseed(seed)
end
if not def.player then if not def.player then
player = nil player = nil
elseif player == nil then elseif player == nil then
@ -70,8 +81,10 @@ function unittests.run_one(idx, counters, out_callback, player, pos)
if not status then if not status then
core.log("error", err) core.log("error", err)
end end
print(string.format("[%s] %s - %dms", printf("[%s] %s - %dms", status and "PASS" or "FAIL", def.name, ms_taken)
status and "PASS" or "FAIL", def.name, ms_taken)) if seed and not status then
printf("Random was seeded to %d", seed)
end
counters.time = counters.time + ms_taken counters.time = counters.time + ms_taken
counters.total = counters.total + 1 counters.total = counters.total + 1
if status then if status then
@ -160,11 +173,11 @@ function unittests.run_all()
-- Print stats -- Print stats
assert(#unittests.list == counters.total) assert(#unittests.list == counters.total)
print(string.rep("+", 80)) print(string.rep("+", 80))
print(string.format("Devtest Unit Test Results: %s", local passed = counters.total == counters.passed
counters.total == counters.passed and "PASSED" or "FAILED")) printf("Devtest Unit Test Results: %s", passed and "PASSED" or "FAILED")
print(string.format(" %d / %d failed tests.", printf(" %d / %d failed tests.",
counters.total - counters.passed, counters.total)) counters.total - counters.passed, counters.total)
print(string.format(" Testing took %dms total.", counters.time)) printf(" Testing took %dms total.", counters.time)
print(string.rep("+", 80)) print(string.rep("+", 80))
unittests.on_finished(counters.total == counters.passed) unittests.on_finished(counters.total == counters.passed)
return counters.total == counters.passed return counters.total == counters.passed

View file

@ -34,3 +34,70 @@ local function test_raycast_pointabilities(player, pos1)
end end
unittests.register("test_raycast_pointabilities", test_raycast_pointabilities, {map=true}) unittests.register("test_raycast_pointabilities", test_raycast_pointabilities, {map=true})
local function test_raycast_noskip(_, pos)
local function random_point_in_area(min, max)
local extents = max - min
local v = extents:multiply(vector.new(
math.random(),
math.random(),
math.random()
))
return min + v
end
-- FIXME a variation of this unit test fails in an edge case.
-- This is because Luanti does not handle perfectly diagonal raycasts correctly:
-- Perfect diagonals collide with neither "outside" face and may thus "pierce" nodes.
-- Enable the following code to reproduce:
if 0 == 1 then
pos = vector.new(6, 32, -3)
math.randomseed(1596190898)
function random_point_in_area(min, max)
return min:combine(max, math.random)
end
end
local function cuboid_minmax(extent)
return pos:offset(-extent, -extent, -extent),
pos:offset(extent, extent, extent)
end
-- Carve out a 3x3x3 dirt cuboid in a larger air cuboid
local r = 8
local min, max = cuboid_minmax(r + 1)
local vm = core.get_voxel_manip(min, max)
local old_data = vm:get_data()
local data = vm:get_data()
local emin, emax = vm:get_emerged_area()
local va = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
for index in va:iterp(min, max) do
data[index] = core.CONTENT_AIR
end
for index in va:iterp(cuboid_minmax(1)) do
data[index] = core.get_content_id("basenodes:dirt")
end
vm:set_data(data)
vm:write_to_map()
-- Raycast many times from outside the cuboid
for _ = 1, 100 do
local ray_start
repeat
ray_start = random_point_in_area(cuboid_minmax(r))
until not ray_start:in_area(cuboid_minmax(1.501))
-- Pick a random position inside the dirt
local ray_end = random_point_in_area(cuboid_minmax(1.499))
-- The first pointed thing should have only air "in front" of it,
-- or a dirt node got falsely skipped.
local pt = core.raycast(ray_start, ray_end, false, false):next()
if pt then
assert(core.get_node(pt.above).name == "air")
end
end
vm:set_data(old_data)
vm:write_to_map()
end
unittests.register("test_raycast_noskip", test_raycast_noskip, {map = true, random = true})

View file

@ -34,7 +34,7 @@ enum E_DEBUG_SCENE_TYPE
EDS_BBOX_ALL = EDS_BBOX | EDS_BBOX_BUFFERS, EDS_BBOX_ALL = EDS_BBOX | EDS_BBOX_BUFFERS,
//! Show all debug infos //! Show all debug infos
EDS_FULL = 0xffffffff EDS_FULL = 0xffff
}; };
} // end namespace scene } // end namespace scene

View file

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "IGUIElement.h" #include "IGUIElement.h"
#include "SColor.h"
namespace irr namespace irr
{ {

View file

@ -10,7 +10,6 @@
#include "IEventReceiver.h" #include "IEventReceiver.h"
#include "EGUIElementTypes.h" #include "EGUIElementTypes.h"
#include "EGUIAlignment.h" #include "EGUIAlignment.h"
#include "IGUIEnvironment.h"
#include <cassert> #include <cassert>
#include <list> #include <list>
#include <vector> #include <vector>
@ -19,6 +18,8 @@ namespace irr
{ {
namespace gui namespace gui
{ {
class IGUIEnvironment;
//! Base class of all GUI elements. //! Base class of all GUI elements.
class IGUIElement : virtual public IReferenceCounted, public IEventReceiver class IGUIElement : virtual public IReferenceCounted, public IEventReceiver
{ {

View file

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "IGUIElement.h" #include "IGUIElement.h"
#include "SColor.h"
namespace irr namespace irr
{ {

View file

@ -387,6 +387,14 @@ public:
pass currently is active they can render the correct part of their geometry. */ pass currently is active they can render the correct part of their geometry. */
virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0;
/**
* Sets debug data flags that will be set on every rendered scene node.
* Refer to `E_DEBUG_SCENE_TYPE`.
* @param setBits bit mask of types to enable
* @param unsetBits bit mask of types to disable
*/
virtual void setGlobalDebugData(u16 setBits, u16 unsetBits) = 0;
//! Creates a new scene manager. //! Creates a new scene manager.
/** This can be used to easily draw and/or store two /** This can be used to easily draw and/or store two
independent scenes at the same time. The mesh cache will be independent scenes at the same time. The mesh cache will be

View file

@ -403,14 +403,14 @@ public:
their geometry because it is their only reason for existence, their geometry because it is their only reason for existence,
for example the OctreeSceneNode. for example the OctreeSceneNode.
\param state The culling state to be used. Check E_CULLING_TYPE for possible values.*/ \param state The culling state to be used. Check E_CULLING_TYPE for possible values.*/
void setAutomaticCulling(u32 state) void setAutomaticCulling(u16 state)
{ {
AutomaticCullingState = state; AutomaticCullingState = state;
} }
//! Gets the automatic culling state. //! Gets the automatic culling state.
/** \return The automatic culling state. */ /** \return The automatic culling state. */
u32 getAutomaticCulling() const u16 getAutomaticCulling() const
{ {
return AutomaticCullingState; return AutomaticCullingState;
} }
@ -419,7 +419,7 @@ public:
/** A bitwise OR of the types from @ref irr::scene::E_DEBUG_SCENE_TYPE. /** A bitwise OR of the types from @ref irr::scene::E_DEBUG_SCENE_TYPE.
Please note that not all scene nodes support all debug data types. Please note that not all scene nodes support all debug data types.
\param state The debug data visibility state to be used. */ \param state The debug data visibility state to be used. */
virtual void setDebugDataVisible(u32 state) virtual void setDebugDataVisible(u16 state)
{ {
DebugDataVisible = state; DebugDataVisible = state;
} }
@ -427,7 +427,7 @@ public:
//! Returns if debug data like bounding boxes are drawn. //! Returns if debug data like bounding boxes are drawn.
/** \return A bitwise OR of the debug data values from /** \return A bitwise OR of the debug data values from
@ref irr::scene::E_DEBUG_SCENE_TYPE that are currently visible. */ @ref irr::scene::E_DEBUG_SCENE_TYPE that are currently visible. */
u32 isDebugDataVisible() const u16 isDebugDataVisible() const
{ {
return DebugDataVisible; return DebugDataVisible;
} }
@ -581,10 +581,10 @@ protected:
s32 ID; s32 ID;
//! Automatic culling state //! Automatic culling state
u32 AutomaticCullingState; u16 AutomaticCullingState;
//! Flag if debug data should be drawn, such as Bounding Boxes. //! Flag if debug data should be drawn, such as Bounding Boxes.
u32 DebugDataVisible; u16 DebugDataVisible;
//! Is the node visible? //! Is the node visible?
bool IsVisible; bool IsVisible;

View file

@ -20,7 +20,7 @@ class ITexture;
//! Flag for MaterialTypeParam (in combination with EMT_ONETEXTURE_BLEND) or for BlendFactor //! Flag for MaterialTypeParam (in combination with EMT_ONETEXTURE_BLEND) or for BlendFactor
//! BlendFunc = source * sourceFactor + dest * destFactor //! BlendFunc = source * sourceFactor + dest * destFactor
enum E_BLEND_FACTOR enum E_BLEND_FACTOR : u8
{ {
EBF_ZERO = 0, //!< src & dest (0, 0, 0, 0) EBF_ZERO = 0, //!< src & dest (0, 0, 0, 0)
EBF_ONE, //!< src & dest (1, 1, 1, 1) EBF_ONE, //!< src & dest (1, 1, 1, 1)
@ -36,7 +36,7 @@ enum E_BLEND_FACTOR
}; };
//! Values defining the blend operation //! Values defining the blend operation
enum E_BLEND_OPERATION enum E_BLEND_OPERATION : u8
{ {
EBO_NONE = 0, //!< No blending happens EBO_NONE = 0, //!< No blending happens
EBO_ADD, //!< Default blending adds the color values EBO_ADD, //!< Default blending adds the color values
@ -51,7 +51,7 @@ enum E_BLEND_OPERATION
}; };
//! MaterialTypeParam: e.g. DirectX: D3DTOP_MODULATE, D3DTOP_MODULATE2X, D3DTOP_MODULATE4X //! MaterialTypeParam: e.g. DirectX: D3DTOP_MODULATE, D3DTOP_MODULATE2X, D3DTOP_MODULATE4X
enum E_MODULATE_FUNC enum E_MODULATE_FUNC : u8
{ {
EMFN_MODULATE_1X = 1, EMFN_MODULATE_1X = 1,
EMFN_MODULATE_2X = 2, EMFN_MODULATE_2X = 2,
@ -59,7 +59,7 @@ enum E_MODULATE_FUNC
}; };
//! Comparison function, e.g. for depth buffer test //! Comparison function, e.g. for depth buffer test
enum E_COMPARISON_FUNC enum E_COMPARISON_FUNC : u8
{ {
//! Depth test disabled (disable also write to depth buffer) //! Depth test disabled (disable also write to depth buffer)
ECFN_DISABLED = 0, ECFN_DISABLED = 0,
@ -82,7 +82,7 @@ enum E_COMPARISON_FUNC
}; };
//! Enum values for enabling/disabling color planes for rendering //! Enum values for enabling/disabling color planes for rendering
enum E_COLOR_PLANE enum E_COLOR_PLANE : u8
{ {
//! No color enabled //! No color enabled
ECP_NONE = 0, ECP_NONE = 0,
@ -103,7 +103,7 @@ enum E_COLOR_PLANE
//! Source of the alpha value to take //! Source of the alpha value to take
/** This is currently only supported in EMT_ONETEXTURE_BLEND. You can use an /** This is currently only supported in EMT_ONETEXTURE_BLEND. You can use an
or'ed combination of values. Alpha values are modulated (multiplied). */ or'ed combination of values. Alpha values are modulated (multiplied). */
enum E_ALPHA_SOURCE enum E_ALPHA_SOURCE : u8
{ {
//! Use no alpha, somewhat redundant with other settings //! Use no alpha, somewhat redundant with other settings
EAS_NONE = 0, EAS_NONE = 0,
@ -181,7 +181,7 @@ Some drivers don't support a per-material setting of the anti-aliasing
modes. In those cases, FSAA/multisampling is defined by the device mode modes. In those cases, FSAA/multisampling is defined by the device mode
chosen upon creation via irr::SIrrCreationParameters. chosen upon creation via irr::SIrrCreationParameters.
*/ */
enum E_ANTI_ALIASING_MODE enum E_ANTI_ALIASING_MODE : u8
{ {
//! Use to turn off anti-aliasing for this material //! Use to turn off anti-aliasing for this material
EAAM_OFF = 0, EAAM_OFF = 0,
@ -202,7 +202,7 @@ const c8 *const PolygonOffsetDirectionNames[] = {
}; };
//! For SMaterial.ZWriteEnable //! For SMaterial.ZWriteEnable
enum E_ZWRITE enum E_ZWRITE : u8
{ {
//! zwrite always disabled for this material //! zwrite always disabled for this material
EZW_OFF = 0, EZW_OFF = 0,
@ -240,10 +240,10 @@ public:
//! Default constructor. Creates a solid material //! Default constructor. Creates a solid material
SMaterial() : SMaterial() :
MaterialType(EMT_SOLID), ColorParam(0, 0, 0, 0), MaterialType(EMT_SOLID), ColorParam(0, 0, 0, 0),
MaterialTypeParam(0.0f), Thickness(1.0f), ZBuffer(ECFN_LESSEQUAL), MaterialTypeParam(0.0f), Thickness(1.0f), BlendFactor(0.0f),
AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL), PolygonOffsetDepthBias(0.f), PolygonOffsetSlopeScale(0.f),
BlendOperation(EBO_NONE), BlendFactor(0.0f), PolygonOffsetDepthBias(0.f), ZBuffer(ECFN_LESSEQUAL), AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL),
PolygonOffsetSlopeScale(0.f), Wireframe(false), PointCloud(false), BlendOperation(EBO_NONE), Wireframe(false), PointCloud(false),
ZWriteEnable(EZW_AUTO), ZWriteEnable(EZW_AUTO),
BackfaceCulling(true), FrontfaceCulling(false), FogEnable(false), BackfaceCulling(true), FrontfaceCulling(false), FogEnable(false),
UseMipMaps(true) UseMipMaps(true)
@ -268,28 +268,6 @@ public:
//! Thickness of non-3dimensional elements such as lines and points. //! Thickness of non-3dimensional elements such as lines and points.
f32 Thickness; f32 Thickness;
//! Is the ZBuffer enabled? Default: ECFN_LESSEQUAL
/** If you want to disable depth test for this material
just set this parameter to ECFN_DISABLED.
Values are from E_COMPARISON_FUNC. */
u8 ZBuffer;
//! Sets the antialiasing mode
/** Values are chosen from E_ANTI_ALIASING_MODE. Default is
EAAM_SIMPLE, i.e. simple multi-sample anti-aliasing. */
u8 AntiAliasing;
//! Defines the enabled color planes
/** Values are defined as or'ed values of the E_COLOR_PLANE enum.
Only enabled color planes will be rendered to the current render
target. Typical use is to disable all colors when rendering only to
depth or stencil buffer, or using Red and Green for Stereo rendering. */
u8 ColorMask : 4;
//! Store the blend operation of choice
/** Values to be chosen from E_BLEND_OPERATION. */
E_BLEND_OPERATION BlendOperation : 4;
//! Store the blend factors //! Store the blend factors
/** textureBlendFunc/textureBlendFuncSeparate functions should be used to write /** textureBlendFunc/textureBlendFuncSeparate functions should be used to write
properly blending factors to this parameter. properly blending factors to this parameter.
@ -304,11 +282,7 @@ public:
//! A constant z-buffer offset for a polygon/line/point //! A constant z-buffer offset for a polygon/line/point
/** The range of the value is driver specific. /** The range of the value is driver specific.
On OpenGL you get units which are multiplied by the smallest value that is guaranteed to produce a resolvable offset. On OpenGL you get units which are multiplied by the smallest value that is guaranteed to produce a resolvable offset. */
On D3D9 you can pass a range between -1 and 1. But you should likely divide it by the range of the depthbuffer.
Like dividing by 65535.0 for a 16 bit depthbuffer. Thought it still might produce too large of a bias.
Some article (https://aras-p.info/blog/2008/06/12/depth-bias-and-the-power-of-deceiving-yourself/)
recommends multiplying by 2.0*4.8e-7 (and strangely on both 16 bit and 24 bit). */
f32 PolygonOffsetDepthBias; f32 PolygonOffsetDepthBias;
//! Variable Z-Buffer offset based on the slope of the polygon. //! Variable Z-Buffer offset based on the slope of the polygon.
@ -320,6 +294,25 @@ public:
and -1.f to pull them towards the camera. */ and -1.f to pull them towards the camera. */
f32 PolygonOffsetSlopeScale; f32 PolygonOffsetSlopeScale;
//! Is the ZBuffer enabled? Default: ECFN_LESSEQUAL
/** If you want to disable depth test for this material
just set this parameter to ECFN_DISABLED. */
E_COMPARISON_FUNC ZBuffer : 4;
//! Sets the antialiasing mode
/** Default is EAAM_SIMPLE, i.e. simple multi-sample anti-aliasing. */
E_ANTI_ALIASING_MODE AntiAliasing : 4;
//! Defines the enabled color planes
/** Values are defined as or'ed values of the E_COLOR_PLANE enum.
Only enabled color planes will be rendered to the current render
target. Typical use is to disable all colors when rendering only to
depth or stencil buffer, or using Red and Green for Stereo rendering. */
E_COLOR_PLANE ColorMask : 4;
//! Store the blend operation of choice
E_BLEND_OPERATION BlendOperation : 4;
//! Draw as wireframe or filled triangles? Default: false //! Draw as wireframe or filled triangles? Default: false
bool Wireframe : 1; bool Wireframe : 1;

View file

@ -45,7 +45,7 @@ static const char *const aTextureClampNames[] = {
//! Texture minification filter. //! Texture minification filter.
/** Used when scaling textures down. See the documentation on OpenGL's /** Used when scaling textures down. See the documentation on OpenGL's
`GL_TEXTURE_MIN_FILTER` for more information. */ `GL_TEXTURE_MIN_FILTER` for more information. */
enum E_TEXTURE_MIN_FILTER enum E_TEXTURE_MIN_FILTER : u8
{ {
//! Aka nearest-neighbor. //! Aka nearest-neighbor.
ETMINF_NEAREST_MIPMAP_NEAREST = 0, ETMINF_NEAREST_MIPMAP_NEAREST = 0,
@ -61,7 +61,7 @@ enum E_TEXTURE_MIN_FILTER
/** Used when scaling textures up. See the documentation on OpenGL's /** Used when scaling textures up. See the documentation on OpenGL's
`GL_TEXTURE_MAG_FILTER` for more information. `GL_TEXTURE_MAG_FILTER` for more information.
Note that mipmaps are only used for minification, not for magnification. */ Note that mipmaps are only used for minification, not for magnification. */
enum E_TEXTURE_MAG_FILTER enum E_TEXTURE_MAG_FILTER : u8
{ {
//! Aka nearest-neighbor. //! Aka nearest-neighbor.
ETMAGF_NEAREST = 0, ETMAGF_NEAREST = 0,

View file

@ -253,7 +253,7 @@ void CAnimatedMeshSceneNode::render()
// for debug purposes only: // for debug purposes only:
if (DebugDataVisible && PassCount == 1) { if (DebugDataVisible && PassCount == 1) {
video::SMaterial debug_mat; video::SMaterial debug_mat;
debug_mat.AntiAliasing = 0; debug_mat.AntiAliasing = video::EAAM_OFF;
driver->setMaterial(debug_mat); driver->setMaterial(debug_mat);
// show normals // show normals
if (DebugDataVisible & scene::EDS_NORMALS) { if (DebugDataVisible & scene::EDS_NORMALS) {
@ -276,9 +276,6 @@ void CAnimatedMeshSceneNode::render()
debug_mat.ZBuffer = video::ECFN_DISABLED; debug_mat.ZBuffer = video::ECFN_DISABLED;
driver->setMaterial(debug_mat); driver->setMaterial(debug_mat);
if (DebugDataVisible & scene::EDS_BBOX)
driver->draw3DBox(Box, video::SColor(255, 255, 255, 255));
// show bounding box // show bounding box
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) {
for (u32 g = 0; g < m->getMeshBufferCount(); ++g) { for (u32 g = 0; g < m->getMeshBufferCount(); ++g) {
@ -290,6 +287,9 @@ void CAnimatedMeshSceneNode::render()
} }
} }
if (DebugDataVisible & scene::EDS_BBOX)
driver->draw3DBox(Box, video::SColor(255, 255, 255, 255));
// show skeleton // show skeleton
if (DebugDataVisible & scene::EDS_SKELETON) { if (DebugDataVisible & scene::EDS_SKELETON) {
if (Mesh->getMeshType() == EAMT_SKINNED) { if (Mesh->getMeshType() == EAMT_SKINNED) {

View file

@ -91,7 +91,7 @@ public:
private: private:
//! Currently used FileSystemType //! Currently used FileSystemType
EFileSystemType FileSystemType; EFileSystemType FileSystemType = FILESYSTEM_NATIVE;
//! WorkingDirectory for Native and Virtual filesystems //! WorkingDirectory for Native and Virtual filesystems
io::path WorkingDirectory[2]; io::path WorkingDirectory[2];
//! currently attached ArchiveLoaders //! currently attached ArchiveLoaders

View file

@ -948,7 +948,7 @@ IGUIElement *CGUIEnvironment::getNextElement(bool reverse, bool group)
// this element is not part of the tab cycle, // this element is not part of the tab cycle,
// but its parent might be... // but its parent might be...
IGUIElement *el = Focus; IGUIElement *el = Focus;
while (el && el->getParent() && startOrder == -1) { while (el->getParent() && startOrder == -1) {
el = el->getParent(); el = el->getParent();
startOrder = el->getTabOrder(); startOrder = el->getTabOrder();
} }

View file

@ -109,12 +109,10 @@ void CMeshSceneNode::render()
// for debug purposes only: // for debug purposes only:
if (DebugDataVisible && PassCount == 1) { if (DebugDataVisible && PassCount == 1) {
video::SMaterial m; video::SMaterial m;
m.AntiAliasing = 0; m.AntiAliasing = video::EAAM_OFF;
m.ZBuffer = video::ECFN_DISABLED;
driver->setMaterial(m); driver->setMaterial(m);
if (DebugDataVisible & scene::EDS_BBOX) {
driver->draw3DBox(Box, video::SColor(255, 255, 255, 255));
}
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) {
for (u32 g = 0; g < Mesh->getMeshBufferCount(); ++g) { for (u32 g = 0; g < Mesh->getMeshBufferCount(); ++g) {
driver->draw3DBox( driver->draw3DBox(
@ -123,6 +121,10 @@ void CMeshSceneNode::render()
} }
} }
if (DebugDataVisible & scene::EDS_BBOX) {
driver->draw3DBox(Box, video::SColor(255, 255, 255, 255));
}
if (DebugDataVisible & scene::EDS_NORMALS) { if (DebugDataVisible & scene::EDS_NORMALS) {
// draw normals // draw normals
const f32 debugNormalLength = 1.f; const f32 debugNormalLength = 1.f;

View file

@ -619,20 +619,17 @@ void CNullDriver::draw3DBox(const core::aabbox3d<f32> &box, SColor color)
core::vector3df edges[8]; core::vector3df edges[8];
box.getEdges(edges); box.getEdges(edges);
// TODO: optimize into one big drawIndexPrimitive call. video::S3DVertex v[8];
for (u32 i = 0; i < 8; i++) {
v[i].Pos = edges[i];
v[i].Color = color;
}
draw3DLine(edges[5], edges[1], color); const static u16 box_indices[24] = {
draw3DLine(edges[1], edges[3], color); 5, 1, 1, 3, 3, 7, 7, 5, 0, 2, 2, 6, 6, 4, 4, 0, 1, 0, 3, 2, 7, 6, 5, 4
draw3DLine(edges[3], edges[7], color); };
draw3DLine(edges[7], edges[5], color);
draw3DLine(edges[0], edges[2], color); drawVertexPrimitiveList(v, 8, box_indices, 12, EVT_STANDARD, scene::EPT_LINES);
draw3DLine(edges[2], edges[6], color);
draw3DLine(edges[6], edges[4], color);
draw3DLine(edges[4], edges[0], color);
draw3DLine(edges[1], edges[0], color);
draw3DLine(edges[3], edges[2], color);
draw3DLine(edges[7], edges[6], color);
draw3DLine(edges[5], edges[4], color);
} }
//! draws an 2d image //! draws an 2d image
@ -1314,7 +1311,7 @@ void CNullDriver::runOcclusionQuery(scene::ISceneNode *node, bool visible)
OcclusionQueries[index].Run = 0; OcclusionQueries[index].Run = 0;
if (!visible) { if (!visible) {
SMaterial mat; SMaterial mat;
mat.AntiAliasing = 0; mat.AntiAliasing = video::EAAM_OFF;
mat.ColorMask = ECP_NONE; mat.ColorMask = ECP_NONE;
mat.ZWriteEnable = EZW_OFF; mat.ZWriteEnable = EZW_OFF;
setMaterial(mat); setMaterial(mat);

View file

@ -137,6 +137,9 @@ public:
Images.clear(); Images.clear();
} }
if (!name.empty())
Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str());
Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);
TEST_GL_ERROR(Driver); TEST_GL_ERROR(Driver);
@ -247,6 +250,9 @@ public:
break; break;
} }
if (!name.empty())
Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str());
Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);
if (TEST_GL_ERROR(Driver)) { if (TEST_GL_ERROR(Driver)) {
char msg[256]; char msg[256];

View file

@ -2462,66 +2462,6 @@ void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start,
glFogfv(GL_FOG_COLOR, data); glFogfv(GL_FOG_COLOR, data);
} }
//! Draws a 3d box.
void COpenGLDriver::draw3DBox(const core::aabbox3d<f32> &box, SColor color)
{
core::vector3df edges[8];
box.getEdges(edges);
setRenderStates3DMode();
video::S3DVertex v[24];
for (u32 i = 0; i < 24; i++)
v[i].Color = color;
v[0].Pos = edges[5];
v[1].Pos = edges[1];
v[2].Pos = edges[1];
v[3].Pos = edges[3];
v[4].Pos = edges[3];
v[5].Pos = edges[7];
v[6].Pos = edges[7];
v[7].Pos = edges[5];
v[8].Pos = edges[0];
v[9].Pos = edges[2];
v[10].Pos = edges[2];
v[11].Pos = edges[6];
v[12].Pos = edges[6];
v[13].Pos = edges[4];
v[14].Pos = edges[4];
v[15].Pos = edges[0];
v[16].Pos = edges[1];
v[17].Pos = edges[0];
v[18].Pos = edges[3];
v[19].Pos = edges[2];
v[20].Pos = edges[7];
v[21].Pos = edges[6];
v[22].Pos = edges[5];
v[23].Pos = edges[4];
if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra])
getColorBuffer(v, 24, EVT_STANDARD);
CacheHandler->setClientState(true, false, true, false);
glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast<const S3DVertex *>(v))[0].Pos);
#ifdef GL_BGRA
const GLint colorSize = (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) ? GL_BGRA : 4;
#else
const GLint colorSize = 4;
#endif
if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])
glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast<const S3DVertex *>(v))[0].Color);
else {
_IRR_DEBUG_BREAK_IF(ColorBuffer.size() == 0);
glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]);
}
glDrawArrays(GL_LINES, 0, 24);
}
//! Draws a 3d line. //! Draws a 3d line.
void COpenGLDriver::draw3DLine(const core::vector3df &start, void COpenGLDriver::draw3DLine(const core::vector3df &start,
const core::vector3df &end, SColor color) const core::vector3df &end, SColor color)

View file

@ -170,9 +170,6 @@ public:
const core::position2d<s32> &end, const core::position2d<s32> &end,
SColor color = SColor(255, 255, 255, 255)) override; SColor color = SColor(255, 255, 255, 255)) override;
//! Draws a 3d box
void draw3DBox(const core::aabbox3d<f32> &box, SColor color = SColor(255, 255, 255, 255)) override;
//! Draws a 3d line. //! Draws a 3d line.
virtual void draw3DLine(const core::vector3df &start, virtual void draw3DLine(const core::vector3df &start,
const core::vector3df &end, const core::vector3df &end,

View file

@ -1065,6 +1065,10 @@ public:
void irrGlCompressedTexSubImage2D(GLenum target, GLint level, void irrGlCompressedTexSubImage2D(GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLsizei imageSize, const void *data); GLenum format, GLsizei imageSize, const void *data);
inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label)
{
// unimplemented
}
// shader programming // shader programming
void extGlGenPrograms(GLsizei n, GLuint *programs); void extGlGenPrograms(GLsizei n, GLuint *programs);

View file

@ -490,13 +490,19 @@ void CSceneManager::drawAll()
// let all nodes register themselves // let all nodes register themselves
OnRegisterSceneNode(); OnRegisterSceneNode();
const auto &render_node = [this] (ISceneNode *node) {
u32 flags = node->isDebugDataVisible();
node->setDebugDataVisible((flags & DebugDataMask) | DebugDataBits);
node->render();
};
// render camera scenes // render camera scenes
{ {
CurrentRenderPass = ESNRP_CAMERA; CurrentRenderPass = ESNRP_CAMERA;
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
for (auto *node : CameraList) for (auto *node : CameraList)
node->render(); render_node(node);
CameraList.clear(); CameraList.clear();
} }
@ -507,7 +513,7 @@ void CSceneManager::drawAll()
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
for (auto *node : SkyBoxList) for (auto *node : SkyBoxList)
node->render(); render_node(node);
SkyBoxList.clear(); SkyBoxList.clear();
} }
@ -520,7 +526,7 @@ void CSceneManager::drawAll()
std::sort(SolidNodeList.begin(), SolidNodeList.end()); std::sort(SolidNodeList.begin(), SolidNodeList.end());
for (auto &it : SolidNodeList) for (auto &it : SolidNodeList)
it.Node->render(); render_node(it.Node);
SolidNodeList.clear(); SolidNodeList.clear();
} }
@ -533,7 +539,7 @@ void CSceneManager::drawAll()
std::sort(TransparentNodeList.begin(), TransparentNodeList.end()); std::sort(TransparentNodeList.begin(), TransparentNodeList.end());
for (auto &it : TransparentNodeList) for (auto &it : TransparentNodeList)
it.Node->render(); render_node(it.Node);
TransparentNodeList.clear(); TransparentNodeList.clear();
} }
@ -546,7 +552,7 @@ void CSceneManager::drawAll()
std::sort(TransparentEffectNodeList.begin(), TransparentEffectNodeList.end()); std::sort(TransparentEffectNodeList.begin(), TransparentEffectNodeList.end());
for (auto &it : TransparentEffectNodeList) for (auto &it : TransparentEffectNodeList)
it.Node->render(); render_node(it.Node);
TransparentEffectNodeList.clear(); TransparentEffectNodeList.clear();
} }
@ -557,7 +563,7 @@ void CSceneManager::drawAll()
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
for (auto *node : GuiNodeList) for (auto *node : GuiNodeList)
node->render(); render_node(node);
GuiNodeList.clear(); GuiNodeList.clear();
} }

View file

@ -179,6 +179,11 @@ public:
//! Set current render time. //! Set current render time.
void setCurrentRenderPass(E_SCENE_NODE_RENDER_PASS nextPass) override { CurrentRenderPass = nextPass; } void setCurrentRenderPass(E_SCENE_NODE_RENDER_PASS nextPass) override { CurrentRenderPass = nextPass; }
void setGlobalDebugData(u16 setBits, u16 unsetBits) override {
DebugDataMask = ~unsetBits;
DebugDataBits = setBits;
}
//! returns if node is culled //! returns if node is culled
bool isCulled(const ISceneNode *node) const override; bool isCulled(const ISceneNode *node) const override;
@ -268,6 +273,9 @@ private:
//! Mesh cache //! Mesh cache
IMeshCache *MeshCache; IMeshCache *MeshCache;
//! Global debug render state
u16 DebugDataMask = 0, DebugDataBits = 0;
E_SCENE_NODE_RENDER_PASS CurrentRenderPass; E_SCENE_NODE_RENDER_PASS CurrentRenderPass;
}; };

View file

@ -164,13 +164,6 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters &params
ExposedData = ContextManager->getContext(); ExposedData = ContextManager->getContext();
ContextManager->activateContext(ExposedData, false); ContextManager->activateContext(ExposedData, false);
GL.LoadAllProcedures(ContextManager); GL.LoadAllProcedures(ContextManager);
if (EnableErrorTest && GL.IsExtensionPresent("GL_KHR_debug")) {
GL.Enable(GL_DEBUG_OUTPUT);
GL.DebugMessageCallback(debugCb, this);
} else if (EnableErrorTest) {
os::Printer::log("GL debug extension not available");
}
initQuadsIndices();
TEST_GL_ERROR(this); TEST_GL_ERROR(this);
} }
@ -248,6 +241,20 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenS
initFeatures(); initFeatures();
printTextureFormats(); printTextureFormats();
if (EnableErrorTest) {
if (KHRDebugSupported) {
GL.Enable(GL_DEBUG_OUTPUT);
GL.DebugMessageCallback(debugCb, this);
} else {
os::Printer::log("GL debug extension not available");
}
} else {
// don't do debug things if they are not wanted (even if supported)
KHRDebugSupported = false;
}
initQuadsIndices();
// reset cache handler // reset cache handler
delete CacheHandler; delete CacheHandler;
CacheHandler = new COpenGL3CacheHandler(this); CacheHandler = new COpenGL3CacheHandler(this);
@ -1025,9 +1032,7 @@ void COpenGL3DriverBase::drawGeneric(const void *vertices, const void *indexList
GL.DrawElements(GL_TRIANGLE_FAN, primitiveCount + 2, indexSize, indexList); GL.DrawElements(GL_TRIANGLE_FAN, primitiveCount + 2, indexSize, indexList);
break; break;
case scene::EPT_TRIANGLES: case scene::EPT_TRIANGLES:
GL.DrawElements((LastMaterial.Wireframe) ? GL_LINES : (LastMaterial.PointCloud) ? GL_POINTS GL.DrawElements(GL_TRIANGLES, primitiveCount * 3, indexSize, indexList);
: GL_TRIANGLES,
primitiveCount * 3, indexSize, indexList);
break; break;
default: default:
break; break;
@ -1306,7 +1311,28 @@ void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const S
getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact)); getGLBlend(srcAlphaFact), getGLBlend(dstAlphaFact));
} }
// TODO: Polygon Offset. Not sure if it was left out deliberately or if it won't work with this driver. // fillmode
if (Version.Spec != OpenGLSpec::ES && // not supported in gles
(resetAllRenderStates ||
lastmaterial.Wireframe != material.Wireframe ||
lastmaterial.PointCloud != material.PointCloud)) {
GL.PolygonMode(GL_FRONT_AND_BACK,
material.Wireframe ? GL_LINE :
material.PointCloud ? GL_POINT :
GL_FILL);
}
// Polygon Offset
if (resetAllRenderStates ||
lastmaterial.PolygonOffsetDepthBias != material.PolygonOffsetDepthBias ||
lastmaterial.PolygonOffsetSlopeScale != material.PolygonOffsetSlopeScale) {
if (material.PolygonOffsetDepthBias || material.PolygonOffsetSlopeScale) {
GL.Enable(GL.POLYGON_OFFSET_FILL);
GL.PolygonOffset(material.PolygonOffsetSlopeScale, material.PolygonOffsetDepthBias);
} else {
GL.Disable(GL.POLYGON_OFFSET_FILL);
}
}
if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness)
GL.LineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); GL.LineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));
@ -1615,7 +1641,7 @@ s32 COpenGL3DriverBase::addHighLevelShaderMaterial(
s32 nr = -1; s32 nr = -1;
COpenGL3MaterialRenderer *r = new COpenGL3MaterialRenderer( COpenGL3MaterialRenderer *r = new COpenGL3MaterialRenderer(
this, nr, vertexShaderProgram, this, nr, vertexShaderProgram,
pixelShaderProgram, pixelShaderProgram, shaderName,
callback, baseMaterial, userData); callback, baseMaterial, userData);
r->drop(); r->drop();

View file

@ -161,10 +161,23 @@ public:
GL.BlendEquation(mode); GL.BlendEquation(mode);
} }
inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label)
{
if (KHRDebugSupported) {
u32 len = strlen(label);
// Since our texture strings can get quite long we also truncate
// to a hardcoded limit of 82
len = std::min(len, std::min(MaxLabelLength, 82U));
GL.ObjectLabel(identifier, name, len, label);
}
}
bool LODBiasSupported = false; bool LODBiasSupported = false;
bool AnisotropicFilterSupported = false; bool AnisotropicFilterSupported = false;
bool BlendMinMaxSupported = false; bool BlendMinMaxSupported = false;
bool TextureMultisampleSupported = false; bool TextureMultisampleSupported = false;
bool KHRDebugSupported = false;
u32 MaxLabelLength = 0;
}; };
} }

View file

@ -24,6 +24,7 @@ COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver,
s32 &outMaterialTypeNr, s32 &outMaterialTypeNr,
const c8 *vertexShaderProgram, const c8 *vertexShaderProgram,
const c8 *pixelShaderProgram, const c8 *pixelShaderProgram,
const c8 *debugName,
IShaderConstantSetCallBack *callback, IShaderConstantSetCallBack *callback,
E_MATERIAL_TYPE baseMaterial, E_MATERIAL_TYPE baseMaterial,
s32 userData) : s32 userData) :
@ -45,7 +46,7 @@ COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver,
if (CallBack) if (CallBack)
CallBack->grab(); CallBack->grab();
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram); init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, debugName);
} }
COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver, COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver,
@ -98,6 +99,7 @@ GLuint COpenGL3MaterialRenderer::getProgram() const
void COpenGL3MaterialRenderer::init(s32 &outMaterialTypeNr, void COpenGL3MaterialRenderer::init(s32 &outMaterialTypeNr,
const c8 *vertexShaderProgram, const c8 *vertexShaderProgram,
const c8 *pixelShaderProgram, const c8 *pixelShaderProgram,
const c8 *debugName,
bool addMaterial) bool addMaterial)
{ {
outMaterialTypeNr = -1; outMaterialTypeNr = -1;
@ -121,6 +123,9 @@ void COpenGL3MaterialRenderer::init(s32 &outMaterialTypeNr,
if (!linkProgram()) if (!linkProgram())
return; return;
if (debugName)
Driver->irrGlObjectLabel(GL_PROGRAM, Program, debugName);
if (addMaterial) if (addMaterial)
outMaterialTypeNr = Driver->addMaterialRenderer(this); outMaterialTypeNr = Driver->addMaterialRenderer(this);
} }

View file

@ -28,6 +28,7 @@ public:
s32 &outMaterialTypeNr, s32 &outMaterialTypeNr,
const c8 *vertexShaderProgram = 0, const c8 *vertexShaderProgram = 0,
const c8 *pixelShaderProgram = 0, const c8 *pixelShaderProgram = 0,
const c8 *debugName = nullptr,
IShaderConstantSetCallBack *callback = 0, IShaderConstantSetCallBack *callback = 0,
E_MATERIAL_TYPE baseMaterial = EMT_SOLID, E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
s32 userData = 0); s32 userData = 0);
@ -66,7 +67,9 @@ protected:
E_MATERIAL_TYPE baseMaterial = EMT_SOLID, E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
s32 userData = 0); s32 userData = 0);
void init(s32 &outMaterialTypeNr, const c8 *vertexShaderProgram, const c8 *pixelShaderProgram, bool addMaterial = true); void init(s32 &outMaterialTypeNr, const c8 *vertexShaderProgram,
const c8 *pixelShaderProgram, const c8 *debugName = nullptr,
bool addMaterial = true);
bool createShader(GLenum shaderType, const char *shader); bool createShader(GLenum shaderType, const char *shader);
bool linkProgram(); bool linkProgram();

View file

@ -23,8 +23,8 @@ COpenGL3Renderer2D::COpenGL3Renderer2D(const c8 *vertexShaderProgram, const c8 *
WithTexture(withTexture) WithTexture(withTexture)
{ {
int Temp = 0; int Temp = 0;
init(Temp, vertexShaderProgram, pixelShaderProgram,
init(Temp, vertexShaderProgram, pixelShaderProgram, false); withTexture ? "2DTexture" : "2DNoTexture", false);
COpenGL3CacheHandler *cacheHandler = Driver->getCacheHandler(); COpenGL3CacheHandler *cacheHandler = Driver->getCacheHandler();

View file

@ -72,6 +72,9 @@ void COpenGL3Driver::initFeatures()
LODBiasSupported = true; LODBiasSupported = true;
BlendMinMaxSupported = true; BlendMinMaxSupported = true;
TextureMultisampleSupported = true; TextureMultisampleSupported = true;
KHRDebugSupported = isVersionAtLeast(4, 6) || queryExtension("GL_KHR_debug");
if (KHRDebugSupported)
MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH);
// COGLESCoreExtensionHandler::Feature // COGLESCoreExtensionHandler::Feature
static_assert(MATERIAL_MAX_TEXTURES <= 16, "Only up to 16 textures are guaranteed"); static_assert(MATERIAL_MAX_TEXTURES <= 16, "Only up to 16 textures are guaranteed");

View file

@ -124,6 +124,9 @@ void COpenGLES2Driver::initFeatures()
AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic"); AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic");
BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax]; BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax];
TextureMultisampleSupported = isVersionAtLeast(3, 1); TextureMultisampleSupported = isVersionAtLeast(3, 1);
KHRDebugSupported = queryExtension("GL_KHR_debug");
if (KHRDebugSupported)
MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH);
// COGLESCoreExtensionHandler::Feature // COGLESCoreExtensionHandler::Feature
static_assert(MATERIAL_MAX_TEXTURES <= 8, "Only up to 8 textures are guaranteed"); static_assert(MATERIAL_MAX_TEXTURES <= 8, "Only up to 8 textures are guaranteed");

View file

@ -417,7 +417,6 @@ set(independent_SRCS
hud.cpp hud.cpp
inventory.cpp inventory.cpp
itemstackmetadata.cpp itemstackmetadata.cpp
lighting.cpp
log.cpp log.cpp
metadata.cpp metadata.cpp
modchannels.cpp modchannels.cpp

View file

@ -5,7 +5,6 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include "debug.h"
#include "util/container.h" #include "util/container.h"
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "util/basic_macros.h" #include "util/basic_macros.h"

View file

@ -112,7 +112,8 @@ public:
void resize(u32 scrollback); void resize(u32 scrollback);
protected: // Get the current scroll position
s32 getScrollPosition() const { return m_scroll; }
s32 getTopScrollPos() const; s32 getTopScrollPos() const;
s32 getBottomScrollPos() const; s32 getBottomScrollPos() const;

View file

@ -4,10 +4,9 @@
#pragma once #pragma once
#include "util/container.h"
#include <string>
#include <queue>
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "util/container.h" // MutexedQueue
#include <string>
enum ChatEventType { enum ChatEventType {
CET_CHAT, CET_CHAT,

View file

@ -37,6 +37,7 @@
#include "profiler.h" #include "profiler.h"
#include "shader.h" #include "shader.h"
#include "gettext.h" #include "gettext.h"
#include "gettime.h"
#include "clientdynamicinfo.h" #include "clientdynamicinfo.h"
#include "clientmap.h" #include "clientmap.h"
#include "clientmedia.h" #include "clientmedia.h"

View file

@ -91,8 +91,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
init_args(start_data, cmd_args); init_args(start_data, cmd_args);
#if USE_SOUND #if USE_SOUND
if (g_settings->getBool("enable_sound")) g_sound_manager_singleton = createSoundManagerSingleton();
g_sound_manager_singleton = createSoundManagerSingleton();
#endif #endif
if (!init_engine()) if (!init_engine())

View file

@ -445,8 +445,8 @@ void Clouds::readSettings()
// chosen to avoid exactly that. // chosen to avoid exactly that.
// refer to vertex_count in updateMesh() // refer to vertex_count in updateMesh()
m_enable_3d = g_settings->getBool("enable_3d_clouds"); m_enable_3d = g_settings->getBool("enable_3d_clouds");
const u16 maximum = m_enable_3d ? 62 : 25; const u16 maximum = !m_enable_3d ? 62 : 25;
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum); m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 8, maximum);
invalidateMesh(); invalidateMesh();
} }

View file

@ -656,25 +656,33 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
} }
} else if (m_prop.visual == "upright_sprite") { } else if (m_prop.visual == "upright_sprite") {
grabMatrixNode(); grabMatrixNode();
scene::SMesh *mesh = new scene::SMesh(); auto mesh = make_irr<scene::SMesh>();
double dx = BS * m_prop.visual_size.X / 2; f32 dx = BS * m_prop.visual_size.X / 2;
double dy = BS * m_prop.visual_size.Y / 2; f32 dy = BS * m_prop.visual_size.Y / 2;
video::SColor c(0xFFFFFFFF); video::SColor c(0xFFFFFFFF);
{ // Front video::S3DVertex vertices[4] = {
scene::IMeshBuffer *buf = new scene::SMeshBuffer(); video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
video::S3DVertex vertices[4] = { video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1), video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0),
video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1), video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0),
video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0), };
video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0), if (m_is_player) {
}; // Move minimal Y position to 0 (feet position)
if (m_is_player) { for (auto &vertex : vertices)
// Move minimal Y position to 0 (feet position) vertex.Pos.Y += dy;
for (video::S3DVertex &vertex : vertices) }
vertex.Pos.Y += dy; const u16 indices[] = {0,1,2,2,3,0};
for (int face : {0, 1}) {
auto buf = make_irr<scene::SMeshBuffer>();
// Front (0) or Back (1)
if (face == 1) {
for (auto &v : vertices)
v.Normal *= -1;
for (int i : {0, 2})
std::swap(vertices[i].Pos, vertices[i+1].Pos);
} }
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6); buf->append(vertices, 4, indices, 6);
// Set material // Set material
@ -682,36 +690,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
buf->getMaterial().ColorParam = c; buf->getMaterial().ColorParam = c;
// Add to mesh // Add to mesh
mesh->addMeshBuffer(buf); mesh->addMeshBuffer(buf.get());
buf->drop();
} }
{ // Back
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
video::S3DVertex vertices[4] = {
video::S3DVertex( dx,-dy, 0, 0,0,-1, c, 1,1),
video::S3DVertex(-dx,-dy, 0, 0,0,-1, c, 0,1),
video::S3DVertex(-dx, dy, 0, 0,0,-1, c, 0,0),
video::S3DVertex( dx, dy, 0, 0,0,-1, c, 1,0),
};
if (m_is_player) {
// Move minimal Y position to 0 (feet position)
for (video::S3DVertex &vertex : vertices)
vertex.Pos.Y += dy;
}
u16 indices[] = {0,1,2,2,3,0};
buf->append(vertices, 4, indices, 6);
// Set material mesh->recalculateBoundingBox();
setMaterial(buf->getMaterial()); m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode);
buf->getMaterial().ColorParam = c;
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
}
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab(); m_meshnode->grab();
mesh->drop();
} else if (m_prop.visual == "cube") { } else if (m_prop.visual == "cube") {
grabMatrixNode(); grabMatrixNode();
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));

View file

@ -4,15 +4,23 @@
#pragma once #pragma once
#include <map> #include "EMaterialTypes.h"
#include "irrlichttypes_extrabloated.h" #include "IDummyTransformationSceneNode.h"
#include "clientobject.h" #include "irrlichttypes.h"
#include "object_properties.h" #include "object_properties.h"
#include "itemgroup.h" #include "clientobject.h"
#include "constants.h" #include "constants.h"
#include "itemgroup.h"
#include <cassert> #include <cassert>
#include <map>
#include <memory> #include <memory>
namespace irr::scene {
class IMeshSceneNode;
class IBillboardSceneNode;
}
class Camera; class Camera;
class Client; class Client;
struct Nametag; struct Nametag;

View file

@ -62,46 +62,44 @@ const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_railli
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output): MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output):
data(input), data(input),
collector(output), collector(output),
nodedef(data->nodedef), nodedef(data->m_nodedef),
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE), blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE)
smooth_liquids(g_settings->getBool("enable_water_reflections"))
{ {
} }
void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special) void MapblockMeshGenerator::useTile(TileSpec *tile_ret, int index, u8 set_flags,
u8 reset_flags, bool special)
{ {
if (special) if (special)
getSpecialTile(index, &cur_node.tile, cur_node.p == data->m_crack_pos_relative); getSpecialTile(index, tile_ret, cur_node.p == data->m_crack_pos_relative);
else else
getTile(index, &cur_node.tile); getTile(index, tile_ret);
if (!data->m_smooth_lighting)
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
for (auto &layer : cur_node.tile.layers) { for (auto &layer : tile_ret->layers) {
layer.material_flags |= set_flags; layer.material_flags |= set_flags;
layer.material_flags &= ~reset_flags; layer.material_flags &= ~reset_flags;
} }
} }
// Returns a tile, ready for use, non-rotated. // Returns a tile, ready for use, non-rotated.
void MapblockMeshGenerator::getTile(int index, TileSpec *tile) void MapblockMeshGenerator::getTile(int index, TileSpec *tile_ret)
{ {
getNodeTileN(cur_node.n, cur_node.p, index, data, *tile); getNodeTileN(cur_node.n, cur_node.p, index, data, *tile_ret);
} }
// Returns a tile, ready for use, rotated according to the node facedir. // Returns a tile, ready for use, rotated according to the node facedir.
void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile) void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile_ret)
{ {
getNodeTile(cur_node.n, cur_node.p, direction, data, *tile); getNodeTile(cur_node.n, cur_node.p, direction, data, *tile_ret);
} }
// Returns a special tile, ready for use, non-rotated. // Returns a special tile, ready for use, non-rotated.
void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply_crack) void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack)
{ {
*tile = cur_node.f->special_tiles[index]; *tile_ret = cur_node.f->special_tiles[index];
TileLayer *top_layer = nullptr; TileLayer *top_layer = nullptr;
for (auto &layernum : tile->layers) { for (auto &layernum : tile_ret->layers) {
TileLayer *layer = &layernum; TileLayer *layer = &layernum;
if (layer->texture_id == 0) if (layer->texture_id == 0)
continue; continue;
@ -114,7 +112,7 @@ void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply
top_layer->material_flags |= MATERIAL_FLAG_CRACK; top_layer->material_flags |= MATERIAL_FLAG_CRACK;
} }
void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal, void MapblockMeshGenerator::drawQuad(const TileSpec &tile, v3f *coords, const v3s16 &normal,
float vertical_tiling) float vertical_tiling)
{ {
const v2f tcoords[4] = {v2f(0.0, 0.0), v2f(1.0, 0.0), const v2f tcoords[4] = {v2f(0.0, 0.0), v2f(1.0, 0.0),
@ -128,15 +126,17 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
if (data->m_smooth_lighting) if (data->m_smooth_lighting)
vertices[j].Color = blendLightColor(coords[j]); vertices[j].Color = blendLightColor(coords[j]);
else else
vertices[j].Color = cur_node.color; vertices[j].Color = cur_node.lcolor;
if (shade_face) if (shade_face)
applyFacesShading(vertices[j].Color, normal2); applyFacesShading(vertices[j].Color, normal2);
vertices[j].TCoords = tcoords[j]; vertices[j].TCoords = tcoords[j];
} }
collector->append(cur_node.tile, vertices, 4, quad_indices, 6); collector->append(tile, vertices, 4, quad_indices, 6);
} }
static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box, const f32 *txc, TileSpec *tiles, int tilecount) { static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box,
const f32 *txc, const TileSpec *tiles, int tilecount)
{
v3f min = box.MinEdge; v3f min = box.MinEdge;
v3f max = box.MaxEdge; v3f max = box.MaxEdge;
@ -218,7 +218,7 @@ enum class QuadDiagonal {
// and to choose diagonal to split the quad at. // and to choose diagonal to split the quad at.
template <typename Fn> template <typename Fn>
void MapblockMeshGenerator::drawCuboid(const aabb3f &box, void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter) const TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter)
{ {
assert(tilecount >= 1 && tilecount <= 6); // pre-condition assert(tilecount >= 1 && tilecount <= 6); // pre-condition
@ -238,16 +238,16 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
void MapblockMeshGenerator::getSmoothLightFrame() void MapblockMeshGenerator::getSmoothLightFrame()
{ {
for (int k = 0; k < 8; ++k) for (int k = 0; k < 8; ++k)
cur_node.frame.sunlight[k] = false; cur_node.lframe.sunlight[k] = false;
for (int k = 0; k < 8; ++k) { for (int k = 0; k < 8; ++k) {
LightPair light(getSmoothLightTransparent(blockpos_nodes + cur_node.p, light_dirs[k], data)); LightPair light(getSmoothLightTransparent(blockpos_nodes + cur_node.p, light_dirs[k], data));
cur_node.frame.lightsDay[k] = light.lightDay; cur_node.lframe.lightsDay[k] = light.lightDay;
cur_node.frame.lightsNight[k] = light.lightNight; cur_node.lframe.lightsNight[k] = light.lightNight;
// If there is direct sunlight and no ambient occlusion at some corner, // If there is direct sunlight and no ambient occlusion at some corner,
// mark the vertical edge (top and bottom corners) containing it. // mark the vertical edge (top and bottom corners) containing it.
if (light.lightDay == 255) { if (light.lightDay == 255) {
cur_node.frame.sunlight[k] = true; cur_node.lframe.sunlight[k] = true;
cur_node.frame.sunlight[k ^ 2] = true; cur_node.lframe.sunlight[k ^ 2] = true;
} }
} }
} }
@ -270,9 +270,9 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos)
f32 dy = (k & 2) ? y : 1 - y; f32 dy = (k & 2) ? y : 1 - y;
f32 dz = (k & 1) ? z : 1 - z; f32 dz = (k & 1) ? z : 1 - z;
// Use direct sunlight (255), if any; use daylight otherwise. // Use direct sunlight (255), if any; use daylight otherwise.
f32 light_boosted = cur_node.frame.sunlight[k] ? 255 : cur_node.frame.lightsDay[k]; f32 light_boosted = cur_node.lframe.sunlight[k] ? 255 : cur_node.lframe.lightsDay[k];
lightDay += dx * dy * dz * cur_node.frame.lightsDay[k]; lightDay += dx * dy * dz * cur_node.lframe.lightsDay[k];
lightNight += dx * dy * dz * cur_node.frame.lightsNight[k]; lightNight += dx * dy * dz * cur_node.lframe.lightsNight[k];
lightBoosted += dx * dy * dz * light_boosted; lightBoosted += dx * dy * dz * light_boosted;
} }
return LightInfo{lightDay, lightNight, lightBoosted}; return LightInfo{lightDay, lightNight, lightBoosted};
@ -280,7 +280,6 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos)
// Calculates vertex color to be used in mapblock mesh // Calculates vertex color to be used in mapblock mesh
// vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so) // vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so)
// tile_color - node's tile color
video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos) video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos)
{ {
LightInfo light = blendLight(vertex_pos); LightInfo light = blendLight(vertex_pos);
@ -323,8 +322,14 @@ static inline int lightDiff(LightPair a, LightPair b)
return abs(a.lightDay - b.lightDay) + abs(a.lightNight - b.lightNight); return abs(a.lightDay - b.lightDay) + abs(a.lightNight - b.lightNight);
} }
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc, void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const TileSpec &tile,
TileSpec *tiles, int tile_count, u8 mask) const f32 *txc, u8 mask)
{
drawAutoLightedCuboid(box, &tile, 1, txc, mask);
}
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box,
const TileSpec *tiles, int tile_count, const f32 *txc, u8 mask)
{ {
bool scale = std::fabs(cur_node.f->visual_scale - 1.0f) > 1e-3f; bool scale = std::fabs(cur_node.f->visual_scale - 1.0f) > 1e-3f;
f32 texture_coord_buf[24]; f32 texture_coord_buf[24];
@ -348,10 +353,6 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
generateCuboidTextureCoords(box, texture_coord_buf); generateCuboidTextureCoords(box, texture_coord_buf);
txc = texture_coord_buf; txc = texture_coord_buf;
} }
if (!tiles) {
tiles = &cur_node.tile;
tile_count = 1;
}
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
LightInfo lights[8]; LightInfo lights[8];
for (int j = 0; j < 8; ++j) { for (int j = 0; j < 8; ++j) {
@ -377,7 +378,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
}); });
} else { } else {
drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) { drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) {
video::SColor color = encode_light(cur_node.light, cur_node.f->light_source); video::SColor color = cur_node.lcolor;
if (!cur_node.f->light_source) if (!cur_node.f->light_source)
applyFacesShading(color, vertices[0].Normal); applyFacesShading(color, vertices[0].Normal);
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
@ -540,19 +541,20 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing()
if (data->m_smooth_lighting) if (data->m_smooth_lighting)
return; // don't need to pre-compute anything in this case return; // don't need to pre-compute anything in this case
auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
if (cur_node.f->light_source != 0) { if (cur_node.f->light_source != 0) {
// If this liquid emits light and doesn't contain light, draw // If this liquid emits light and doesn't contain light, draw
// it at what it emits, for an increased effect // it at what it emits, for an increased effect
u8 e = decode_light(cur_node.f->light_source); u8 e = decode_light(cur_node.f->light_source);
cur_node.light = LightPair(std::max(e, cur_node.light.lightDay), light = LightPair(std::max(e, light.lightDay),
std::max(e, cur_node.light.lightNight)); std::max(e, light.lightNight));
} else if (nodedef->getLightingFlags(ntop).has_light) { } else if (nodedef->getLightingFlags(ntop).has_light) {
// Otherwise, use the light of the node on top if possible // Otherwise, use the light of the node on top if possible
cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); light = LightPair(getInteriorLight(ntop, 0, nodedef));
} }
cur_liquid.color_top = encode_light(cur_node.light, cur_node.f->light_source); cur_liquid.color_top = encode_light(light, cur_node.f->light_source);
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source); cur_node.lcolor = encode_light(light, cur_node.f->light_source);
} }
void MapblockMeshGenerator::getLiquidNeighborhood() void MapblockMeshGenerator::getLiquidNeighborhood()
@ -695,10 +697,18 @@ void MapblockMeshGenerator::drawLiquidSides()
v += 0.5f - cur_liquid.corner_levels[base.Z][base.X]; v += 0.5f - cur_liquid.corner_levels[base.Z][base.X];
} }
video::SColor color;
if (data->m_smooth_lighting) if (data->m_smooth_lighting)
cur_node.color = blendLightColor(pos); color = blendLightColor(pos);
else
color = cur_node.lcolor;
pos += cur_node.origin; pos += cur_node.origin;
vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, face.dir.X, face.dir.Y, face.dir.Z, cur_node.color, vertex.u, v);
vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z,
face.dir.X, face.dir.Y, face.dir.Z,
color,
vertex.u, v);
}; };
collector->append(cur_liquid.tile, vertices, 4, quad_indices, 6); collector->append(cur_liquid.tile, vertices, 4, quad_indices, 6);
} }
@ -722,7 +732,7 @@ void MapblockMeshGenerator::drawLiquidTop()
int u = corner_resolve[i][0]; int u = corner_resolve[i][0];
int w = corner_resolve[i][1]; int w = corner_resolve[i][1];
if (smooth_liquids) { if (data->m_enable_water_reflections) {
int x = vertices[i].Pos.X > 0; int x = vertices[i].Pos.X > 0;
int z = vertices[i].Pos.Z > 0; int z = vertices[i].Pos.Z > 0;
@ -774,7 +784,7 @@ void MapblockMeshGenerator::drawLiquidTop()
vertex.TCoords += tcoord_translate; vertex.TCoords += tcoord_translate;
if (!smooth_liquids) { if (!data->m_enable_water_reflections) {
vertex.Normal = v3f(dx, 1., dz).normalize(); vertex.Normal = v3f(dx, 1., dz).normalize();
} }
} }
@ -816,7 +826,8 @@ void MapblockMeshGenerator::drawLiquidNode()
void MapblockMeshGenerator::drawGlasslikeNode() void MapblockMeshGenerator::drawGlasslikeNode()
{ {
useTile(0, 0, 0); TileSpec tile;
useTile(&tile, 0, 0, 0);
for (int face = 0; face < 6; face++) { for (int face = 0; face < 6; face++) {
// Check this neighbor // Check this neighbor
@ -850,7 +861,7 @@ void MapblockMeshGenerator::drawGlasslikeNode()
vertex.rotateXZBy(-90); break; vertex.rotateXZBy(-90); break;
} }
} }
drawQuad(vertices, dir); drawQuad(tile, vertices, dir);
} }
} }
@ -860,9 +871,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
for (int face = 0; face < 6; face++) for (int face = 0; face < 6; face++)
getTile(g_6dirs[face], &tiles[face]); getTile(g_6dirs[face], &tiles[face]);
if (!data->m_smooth_lighting)
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
TileSpec glass_tiles[6]; TileSpec glass_tiles[6];
for (auto &glass_tile : glass_tiles) for (auto &glass_tile : glass_tiles)
glass_tile = tiles[4]; glass_tile = tiles[4];
@ -934,7 +942,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
{0, 1, 8}, {0, 4, 16}, {3, 4, 17}, {3, 1, 9}, {0, 1, 8}, {0, 4, 16}, {3, 4, 17}, {3, 1, 9},
}; };
cur_node.tile = tiles[1];
for (int edge = 0; edge < FRAMED_EDGE_COUNT; edge++) { for (int edge = 0; edge < FRAMED_EDGE_COUNT; edge++) {
bool edge_invisible; bool edge_invisible;
if (nb[nb_triplet[edge][2]]) if (nb[nb_triplet[edge][2]])
@ -943,14 +950,13 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]]; edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]];
if (edge_invisible) if (edge_invisible)
continue; continue;
drawAutoLightedCuboid(frame_edges[edge]); drawAutoLightedCuboid(frame_edges[edge], tiles[1]);
} }
for (int face = 0; face < 6; face++) { for (int face = 0; face < 6; face++) {
if (nb[face]) if (nb[face])
continue; continue;
cur_node.tile = glass_tiles[face];
// Face at Z- // Face at Z-
v3f vertices[4] = { v3f vertices[4] = {
v3f(-a, a, -g), v3f(-a, a, -g),
@ -976,7 +982,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
} }
} }
v3s16 dir = g_6dirs[face]; v3s16 dir = g_6dirs[face];
drawQuad(vertices, dir); drawQuad(glass_tiles[face], vertices, dir);
} }
// Optionally render internal liquid level defined by param2 // Optionally render internal liquid level defined by param2
@ -986,13 +992,18 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
// Internal liquid level has param2 range 0 .. 63, // Internal liquid level has param2 range 0 .. 63,
// convert it to -0.5 .. 0.5 // convert it to -0.5 .. 0.5
float vlev = (param2 / 63.0f) * 2.0f - 1.0f; float vlev = (param2 / 63.0f) * 2.0f - 1.0f;
getSpecialTile(0, &cur_node.tile); TileSpec tile;
drawAutoLightedCuboid(aabb3f(-(nb[5] ? g : b), getSpecialTile(0, &tile);
-(nb[4] ? g : b), drawAutoLightedCuboid(
-(nb[3] ? g : b), aabb3f(
(nb[2] ? g : b), -(nb[5] ? g : b),
(nb[1] ? g : b) * vlev, -(nb[4] ? g : b),
(nb[0] ? g : b))); -(nb[3] ? g : b),
(nb[2] ? g : b),
(nb[1] ? g : b) * vlev,
(nb[0] ? g : b)
),
tile);
} }
} }
@ -1007,7 +1018,8 @@ void MapblockMeshGenerator::drawTorchlikeNode()
case DWM_S2: tileindex = 0; break; // floor, but rotated case DWM_S2: tileindex = 0; break; // floor, but rotated
default: tileindex = 2; // side (or invalid, shouldn't happen) default: tileindex = 2; // side (or invalid, shouldn't happen)
} }
useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); TileSpec tile;
useTile(&tile, tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
float size = BS / 2 * cur_node.f->visual_scale; float size = BS / 2 * cur_node.f->visual_scale;
v3f vertices[4] = { v3f vertices[4] = {
@ -1054,13 +1066,14 @@ void MapblockMeshGenerator::drawTorchlikeNode()
break; break;
} }
} }
drawQuad(vertices); drawQuad(tile, vertices);
} }
void MapblockMeshGenerator::drawSignlikeNode() void MapblockMeshGenerator::drawSignlikeNode()
{ {
u8 wall = cur_node.n.getWallMounted(nodedef); u8 wall = cur_node.n.getWallMounted(nodedef);
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); TileSpec tile;
useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
static const float offset = BS / 16; static const float offset = BS / 16;
float size = BS / 2 * cur_node.f->visual_scale; float size = BS / 2 * cur_node.f->visual_scale;
// Wall at X+ of node // Wall at X+ of node
@ -1091,13 +1104,13 @@ void MapblockMeshGenerator::drawSignlikeNode()
vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break; vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break;
} }
} }
drawQuad(vertices); drawQuad(tile, vertices);
} }
void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset, void MapblockMeshGenerator::drawPlantlikeQuad(const TileSpec &tile,
bool offset_top_only) float rotation, float quad_offset, bool offset_top_only)
{ {
const f32 scale = cur_node.scale; const f32 scale = cur_plant.scale;
v3f vertices[4] = { v3f vertices[4] = {
v3f(-scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0), v3f(-scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0),
v3f( scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0), v3f( scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0),
@ -1147,14 +1160,14 @@ void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
} }
} }
drawQuad(vertices, v3s16(0, 0, 0), cur_plant.plant_height); drawQuad(tile, vertices, v3s16(0, 0, 0), cur_plant.plant_height);
} }
void MapblockMeshGenerator::drawPlantlike(bool is_rooted) void MapblockMeshGenerator::drawPlantlike(const TileSpec &tile, bool is_rooted)
{ {
cur_plant.draw_style = PLANT_STYLE_CROSS; cur_plant.draw_style = PLANT_STYLE_CROSS;
cur_node.scale = BS / 2 * cur_node.f->visual_scale;
cur_plant.offset = v3f(0, 0, 0); cur_plant.offset = v3f(0, 0, 0);
cur_plant.scale = BS / 2 * cur_node.f->visual_scale;
cur_plant.rotate_degree = 0.0f; cur_plant.rotate_degree = 0.0f;
cur_plant.random_offset_Y = false; cur_plant.random_offset_Y = false;
cur_plant.face_num = 0; cur_plant.face_num = 0;
@ -1164,7 +1177,7 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
case CPT2_MESHOPTIONS: case CPT2_MESHOPTIONS:
cur_plant.draw_style = PlantlikeStyle(cur_node.n.param2 & MO_MASK_STYLE); cur_plant.draw_style = PlantlikeStyle(cur_node.n.param2 & MO_MASK_STYLE);
if (cur_node.n.param2 & MO_BIT_SCALE_SQRT2) if (cur_node.n.param2 & MO_BIT_SCALE_SQRT2)
cur_node.scale *= 1.41421; cur_plant.scale *= 1.41421;
if (cur_node.n.param2 & MO_BIT_RANDOM_OFFSET) { if (cur_node.n.param2 & MO_BIT_RANDOM_OFFSET) {
PseudoRandom rng(cur_node.p.X << 8 | cur_node.p.Z | cur_node.p.Y << 16); PseudoRandom rng(cur_node.p.X << 8 | cur_node.p.Z | cur_node.p.Y << 16);
cur_plant.offset.X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145); cur_plant.offset.X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
@ -1205,63 +1218,66 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
switch (cur_plant.draw_style) { switch (cur_plant.draw_style) {
case PLANT_STYLE_CROSS: case PLANT_STYLE_CROSS:
drawPlantlikeQuad(46); drawPlantlikeQuad(tile, 46);
drawPlantlikeQuad(-44); drawPlantlikeQuad(tile, -44);
break; break;
case PLANT_STYLE_CROSS2: case PLANT_STYLE_CROSS2:
drawPlantlikeQuad(91); drawPlantlikeQuad(tile, 91);
drawPlantlikeQuad(1); drawPlantlikeQuad(tile, 1);
break; break;
case PLANT_STYLE_STAR: case PLANT_STYLE_STAR:
drawPlantlikeQuad(121); drawPlantlikeQuad(tile, 121);
drawPlantlikeQuad(241); drawPlantlikeQuad(tile, 241);
drawPlantlikeQuad(1); drawPlantlikeQuad(tile, 1);
break; break;
case PLANT_STYLE_HASH: case PLANT_STYLE_HASH:
drawPlantlikeQuad( 1, BS / 4); drawPlantlikeQuad(tile, 1, BS / 4);
drawPlantlikeQuad( 91, BS / 4); drawPlantlikeQuad(tile, 91, BS / 4);
drawPlantlikeQuad(181, BS / 4); drawPlantlikeQuad(tile, 181, BS / 4);
drawPlantlikeQuad(271, BS / 4); drawPlantlikeQuad(tile, 271, BS / 4);
break; break;
case PLANT_STYLE_HASH2: case PLANT_STYLE_HASH2:
drawPlantlikeQuad( 1, -BS / 2, true); drawPlantlikeQuad(tile, 1, -BS / 2, true);
drawPlantlikeQuad( 91, -BS / 2, true); drawPlantlikeQuad(tile, 91, -BS / 2, true);
drawPlantlikeQuad(181, -BS / 2, true); drawPlantlikeQuad(tile, 181, -BS / 2, true);
drawPlantlikeQuad(271, -BS / 2, true); drawPlantlikeQuad(tile, 271, -BS / 2, true);
break; break;
} }
} }
void MapblockMeshGenerator::drawPlantlikeNode() void MapblockMeshGenerator::drawPlantlikeNode()
{ {
useTile(); TileSpec tile;
drawPlantlike(); useTile(&tile);
drawPlantlike(tile);
} }
void MapblockMeshGenerator::drawPlantlikeRootedNode() void MapblockMeshGenerator::drawPlantlikeRootedNode()
{ {
drawSolidNode(); drawSolidNode();
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true); TileSpec tile;
useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true);
cur_node.origin += v3f(0.0, BS, 0.0); cur_node.origin += v3f(0.0, BS, 0.0);
cur_node.p.Y++; cur_node.p.Y++;
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
getSmoothLightFrame(); getSmoothLightFrame();
} else { } else {
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p);
cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef)); auto light = LightPair(getInteriorLight(ntop, 0, nodedef));
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
} }
drawPlantlike(true); drawPlantlike(tile, true);
cur_node.p.Y--; cur_node.p.Y--;
} }
void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle, void MapblockMeshGenerator::drawFirelikeQuad(const TileSpec &tile, float rotation,
float offset_h, float offset_v) float opening_angle, float offset_h, float offset_v)
{ {
const f32 scale = cur_node.scale; const f32 scale = BS / 2 * cur_node.f->visual_scale;
v3f vertices[4] = { v3f vertices[4] = {
v3f(-scale, -BS / 2 + scale * 2, 0), v3f(-scale, -BS / 2 + scale * 2, 0),
v3f( scale, -BS / 2 + scale * 2, 0), v3f( scale, -BS / 2 + scale * 2, 0),
@ -1275,13 +1291,13 @@ void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle
vertex.rotateXZBy(rotation); vertex.rotateXZBy(rotation);
vertex.Y += offset_v; vertex.Y += offset_v;
} }
drawQuad(vertices); drawQuad(tile, vertices);
} }
void MapblockMeshGenerator::drawFirelikeNode() void MapblockMeshGenerator::drawFirelikeNode()
{ {
useTile(); TileSpec tile;
cur_node.scale = BS / 2 * cur_node.f->visual_scale; useTile(&tile);
// Check for adjacent nodes // Check for adjacent nodes
bool neighbors = false; bool neighbors = false;
@ -1300,41 +1316,41 @@ void MapblockMeshGenerator::drawFirelikeNode()
bool drawBottomFire = neighbor[D6D_YP]; bool drawBottomFire = neighbor[D6D_YP];
if (drawBasicFire || neighbor[D6D_ZP]) if (drawBasicFire || neighbor[D6D_ZP])
drawFirelikeQuad(0, -10, 0.4 * BS); drawFirelikeQuad(tile, 0, -10, 0.4 * BS);
else if (drawBottomFire) else if (drawBottomFire)
drawFirelikeQuad(0, 70, 0.47 * BS, 0.484 * BS); drawFirelikeQuad(tile, 0, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire || neighbor[D6D_XN]) if (drawBasicFire || neighbor[D6D_XN])
drawFirelikeQuad(90, -10, 0.4 * BS); drawFirelikeQuad(tile, 90, -10, 0.4 * BS);
else if (drawBottomFire) else if (drawBottomFire)
drawFirelikeQuad(90, 70, 0.47 * BS, 0.484 * BS); drawFirelikeQuad(tile, 90, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire || neighbor[D6D_ZN]) if (drawBasicFire || neighbor[D6D_ZN])
drawFirelikeQuad(180, -10, 0.4 * BS); drawFirelikeQuad(tile, 180, -10, 0.4 * BS);
else if (drawBottomFire) else if (drawBottomFire)
drawFirelikeQuad(180, 70, 0.47 * BS, 0.484 * BS); drawFirelikeQuad(tile, 180, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire || neighbor[D6D_XP]) if (drawBasicFire || neighbor[D6D_XP])
drawFirelikeQuad(270, -10, 0.4 * BS); drawFirelikeQuad(tile, 270, -10, 0.4 * BS);
else if (drawBottomFire) else if (drawBottomFire)
drawFirelikeQuad(270, 70, 0.47 * BS, 0.484 * BS); drawFirelikeQuad(tile, 270, 70, 0.47 * BS, 0.484 * BS);
if (drawBasicFire) { if (drawBasicFire) {
drawFirelikeQuad(45, 0, 0.0); drawFirelikeQuad(tile, 45, 0, 0.0);
drawFirelikeQuad(-45, 0, 0.0); drawFirelikeQuad(tile, -45, 0, 0.0);
} }
} }
void MapblockMeshGenerator::drawFencelikeNode() void MapblockMeshGenerator::drawFencelikeNode()
{ {
useTile(0, 0, 0); TileSpec tile_nocrack;
TileSpec tile_nocrack = cur_node.tile; useTile(&tile_nocrack, 0, 0, 0);
for (auto &layer : tile_nocrack.layers) for (auto &layer : tile_nocrack.layers)
layer.material_flags &= ~MATERIAL_FLAG_CRACK; layer.material_flags &= ~MATERIAL_FLAG_CRACK;
// Put wood the right way around in the posts // Put wood the right way around in the posts
TileSpec tile_rot = cur_node.tile; TileSpec tile_rot = tile_nocrack;
tile_rot.rotation = TileRotation::R90; tile_rot.rotation = TileRotation::R90;
static const f32 post_rad = BS / 8; static const f32 post_rad = BS / 8;
@ -1352,10 +1368,7 @@ void MapblockMeshGenerator::drawFencelikeNode()
0.500, 0.000, 0.750, 1.000, 0.500, 0.000, 0.750, 1.000,
0.750, 0.000, 1.000, 1.000, 0.750, 0.000, 1.000, 1.000,
}; };
cur_node.tile = tile_rot; drawAutoLightedCuboid(post, tile_rot, postuv);
drawAutoLightedCuboid(post, postuv);
cur_node.tile = tile_nocrack;
// Now a section of fence, +X, if there's a post there // Now a section of fence, +X, if there's a post there
v3s16 p2 = cur_node.p; v3s16 p2 = cur_node.p;
@ -1375,8 +1388,8 @@ void MapblockMeshGenerator::drawFencelikeNode()
0.000, 0.500, 1.000, 0.625, 0.000, 0.500, 1.000, 0.625,
0.000, 0.875, 1.000, 1.000, 0.000, 0.875, 1.000, 1.000,
}; };
drawAutoLightedCuboid(bar_x1, xrailuv); drawAutoLightedCuboid(bar_x1, tile_nocrack, xrailuv);
drawAutoLightedCuboid(bar_x2, xrailuv); drawAutoLightedCuboid(bar_x2, tile_nocrack, xrailuv);
} }
// Now a section of fence, +Z, if there's a post there // Now a section of fence, +Z, if there's a post there
@ -1397,8 +1410,8 @@ void MapblockMeshGenerator::drawFencelikeNode()
0.3750, 0.3750, 0.5000, 0.5000, 0.3750, 0.3750, 0.5000, 0.5000,
0.6250, 0.6250, 0.7500, 0.7500, 0.6250, 0.6250, 0.7500, 0.7500,
}; };
drawAutoLightedCuboid(bar_z1, zrailuv); drawAutoLightedCuboid(bar_z1, tile_nocrack, zrailuv);
drawAutoLightedCuboid(bar_z2, zrailuv); drawAutoLightedCuboid(bar_z2, tile_nocrack, zrailuv);
} }
} }
@ -1480,7 +1493,8 @@ void MapblockMeshGenerator::drawRaillikeNode()
angle = rail_kinds[code].angle; angle = rail_kinds[code].angle;
} }
useTile(tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING); TileSpec tile;
useTile(&tile, tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
static const float offset = BS / 64; static const float offset = BS / 64;
static const float size = BS / 2; static const float size = BS / 2;
@ -1494,7 +1508,7 @@ void MapblockMeshGenerator::drawRaillikeNode()
if (angle) if (angle)
for (v3f &vertex : vertices) for (v3f &vertex : vertices)
vertex.rotateXZBy(angle); vertex.rotateXZBy(angle);
drawQuad(vertices); drawQuad(tile, vertices);
} }
namespace { namespace {
@ -1526,7 +1540,7 @@ void MapblockMeshGenerator::drawAllfacesNode()
getTile(nodebox_tile_dirs[face], &tiles[face]); getTile(nodebox_tile_dirs[face], &tiles[face]);
if (data->m_smooth_lighting) if (data->m_smooth_lighting)
getSmoothLightFrame(); getSmoothLightFrame();
drawAutoLightedCuboid(box, nullptr, tiles, 6); drawAutoLightedCuboid(box, tiles, 6);
} }
void MapblockMeshGenerator::drawNodeboxNode() void MapblockMeshGenerator::drawNodeboxNode()
@ -1633,7 +1647,7 @@ void MapblockMeshGenerator::drawNodeboxNode()
for (auto &box : boxes) { for (auto &box : boxes) {
u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors); u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors);
drawAutoLightedCuboid(box, nullptr, tiles, 6, mask); drawAutoLightedCuboid(box, tiles, 6, nullptr, mask);
} }
} }
@ -1678,29 +1692,35 @@ void MapblockMeshGenerator::drawMeshNode()
for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) { for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) {
// Only up to 6 tiles are supported // Only up to 6 tiles are supported
const u32 tile = mesh->getTextureSlot(j); const u32 tile_idx = mesh->getTextureSlot(j);
useTile(MYMIN(tile, 5)); TileSpec tile;
useTile(&tile, MYMIN(tile_idx, 5));
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices(); video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
u32 vertex_count = buf->getVertexCount(); u32 vertex_count = buf->getVertexCount();
// Mesh is always private here. So the lighting is applied to each
// vertex right here.
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
// Mesh is always private here. So the lighting is applied to each
// vertex right here.
for (u32 k = 0; k < vertex_count; k++) { for (u32 k = 0; k < vertex_count; k++) {
video::S3DVertex &vertex = vertices[k]; video::S3DVertex &vertex = vertices[k];
vertex.Color = blendLightColor(vertex.Pos, vertex.Normal); vertex.Color = blendLightColor(vertex.Pos, vertex.Normal);
vertex.Pos += cur_node.origin; vertex.Pos += cur_node.origin;
} }
collector->append(cur_node.tile, vertices, vertex_count,
buf->getIndices(), buf->getIndexCount());
} else { } else {
// Let the collector process colors, etc. bool is_light_source = cur_node.f->light_source != 0;
collector->append(cur_node.tile, vertices, vertex_count, for (u32 k = 0; k < vertex_count; k++) {
buf->getIndices(), buf->getIndexCount(), cur_node.origin, video::S3DVertex &vertex = vertices[k];
cur_node.color, cur_node.f->light_source); video::SColor color = cur_node.lcolor;
if (!is_light_source)
applyFacesShading(color, vertex.Normal);
vertex.Color = color;
vertex.Pos += cur_node.origin;
}
} }
collector->append(tile, vertices, vertex_count,
buf->getIndices(), buf->getIndexCount());
} }
mesh->drop(); mesh->drop();
} }
@ -1725,10 +1745,12 @@ void MapblockMeshGenerator::drawNode()
break; break;
} }
cur_node.origin = intToFloat(cur_node.p, BS); cur_node.origin = intToFloat(cur_node.p, BS);
if (data->m_smooth_lighting) if (data->m_smooth_lighting) {
getSmoothLightFrame(); getSmoothLightFrame();
else } else {
cur_node.light = LightPair(getInteriorLight(cur_node.n, 0, nodedef)); auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
}
switch (cur_node.f->drawtype) { switch (cur_node.f->drawtype) {
case NDT_FLOWINGLIQUID: drawLiquidNode(); break; case NDT_FLOWINGLIQUID: drawLiquidNode(); break;
case NDT_GLASSLIKE: drawGlasslikeNode(); break; case NDT_GLASSLIKE: drawGlasslikeNode(); break;
@ -1751,19 +1773,11 @@ void MapblockMeshGenerator::generate()
{ {
ZoneScoped; ZoneScoped;
for (cur_node.p.Z = 0; cur_node.p.Z < data->side_length; cur_node.p.Z++) for (cur_node.p.Z = 0; cur_node.p.Z < data->m_side_length; cur_node.p.Z++)
for (cur_node.p.Y = 0; cur_node.p.Y < data->side_length; cur_node.p.Y++) for (cur_node.p.Y = 0; cur_node.p.Y < data->m_side_length; cur_node.p.Y++)
for (cur_node.p.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) { for (cur_node.p.X = 0; cur_node.p.X < data->m_side_length; cur_node.p.X++) {
cur_node.n = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p); cur_node.n = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p);
cur_node.f = &nodedef->get(cur_node.n); cur_node.f = &nodedef->get(cur_node.n);
drawNode(); drawNode();
} }
} }
void MapblockMeshGenerator::renderSingle(content_t node, u8 param2)
{
cur_node.p = {0, 0, 0};
cur_node.n = MapNode(node, 0xff, param2);
cur_node.f = &nodedef->get(cur_node.n);
drawNode();
}

View file

@ -47,7 +47,6 @@ class MapblockMeshGenerator
public: public:
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output); MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
void generate(); void generate();
void renderSingle(content_t node, u8 param2 = 0x00);
private: private:
MeshMakeData *const data; MeshMakeData *const data;
@ -59,15 +58,12 @@ private:
// current node // current node
struct { struct {
v3s16 p; v3s16 p; // relative to blockpos_nodes
v3f origin; v3f origin; // p in BS space
MapNode n; MapNode n;
const ContentFeatures *f; const ContentFeatures *f;
LightPair light; LightFrame lframe; // smooth lighting
LightFrame frame; video::SColor lcolor; // unsmooth lighting
video::SColor color;
TileSpec tile;
f32 scale;
} cur_node; } cur_node;
// lighting // lighting
@ -76,21 +72,23 @@ private:
video::SColor blendLightColor(const v3f &vertex_pos); video::SColor blendLightColor(const v3f &vertex_pos);
video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal); video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal);
void useTile(int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY, void useTile(TileSpec *tile_ret, int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY,
u8 reset_flags = 0, bool special = false); u8 reset_flags = 0, bool special = false);
void getTile(int index, TileSpec *tile); void getTile(int index, TileSpec *tile_ret);
void getTile(v3s16 direction, TileSpec *tile); void getTile(v3s16 direction, TileSpec *tile_ret);
void getSpecialTile(int index, TileSpec *tile, bool apply_crack = false); void getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack = false);
// face drawing // face drawing
void drawQuad(v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0), void drawQuad(const TileSpec &tile, v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0),
float vertical_tiling = 1.0); float vertical_tiling = 1.0);
// cuboid drawing! // cuboid drawing!
template <typename Fn> template <typename Fn>
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter); void drawCuboid(const aabb3f &box, const TileSpec *tiles, int tilecount,
const f32 *txc, u8 mask, Fn &&face_lighter);
void generateCuboidTextureCoords(aabb3f const &box, f32 *coords); void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
void drawAutoLightedCuboid(aabb3f box, f32 const *txc = nullptr, TileSpec *tiles = nullptr, int tile_count = 0, u8 mask = 0); void drawAutoLightedCuboid(aabb3f box, const TileSpec &tile, f32 const *txc = nullptr, u8 mask = 0);
void drawAutoLightedCuboid(aabb3f box, const TileSpec *tiles, int tile_count, f32 const *txc = nullptr, u8 mask = 0);
u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const; u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const;
// liquid-specific // liquid-specific
@ -113,7 +111,6 @@ private:
f32 corner_levels[2][2]; f32 corner_levels[2][2];
}; };
LiquidData cur_liquid; LiquidData cur_liquid;
bool smooth_liquids = false;
void prepareLiquidNodeDrawing(); void prepareLiquidNodeDrawing();
void getLiquidNeighborhood(); void getLiquidNeighborhood();
@ -136,6 +133,7 @@ private:
struct PlantlikeData { struct PlantlikeData {
PlantlikeStyle draw_style; PlantlikeStyle draw_style;
v3f offset; v3f offset;
float scale;
float rotate_degree; float rotate_degree;
bool random_offset_Y; bool random_offset_Y;
int face_num; int face_num;
@ -143,12 +141,12 @@ private:
}; };
PlantlikeData cur_plant; PlantlikeData cur_plant;
void drawPlantlikeQuad(float rotation, float quad_offset = 0, void drawPlantlikeQuad(const TileSpec &tile, float rotation, float quad_offset = 0,
bool offset_top_only = false); bool offset_top_only = false);
void drawPlantlike(bool is_rooted = false); void drawPlantlike(const TileSpec &tile, bool is_rooted = false);
// firelike-specific // firelike-specific
void drawFirelikeQuad(float rotation, float opening_angle, void drawFirelikeQuad(const TileSpec &tile, float rotation, float opening_angle,
float offset_h, float offset_v = 0.0); float offset_h, float offset_v = 0.0);
// drawtypes // drawtypes

View file

@ -472,6 +472,8 @@ public:
const static float object_hit_delay = 0.2; const static float object_hit_delay = 0.2;
const static u16 bbox_debug_flag = scene::EDS_BBOX_ALL;
/* The reason the following structs are not anonymous structs within the /* The reason the following structs are not anonymous structs within the
* class is that they are not used by the majority of member functions and * class is that they are not used by the majority of member functions and
* many functions that do require objects of thse types do not modify them * many functions that do require objects of thse types do not modify them
@ -680,6 +682,8 @@ protected:
private: private:
struct Flags { struct Flags {
bool disable_camera_update = false; bool disable_camera_update = false;
/// 0 = no debug text active, see toggleDebug() for the rest
int debug_state = 0;
}; };
void pauseAnimation(); void pauseAnimation();
@ -782,11 +786,8 @@ private:
* (as opposed to the this local caching). This can be addressed in * (as opposed to the this local caching). This can be addressed in
* a later release. * a later release.
*/ */
bool m_cache_disable_escape_sequences;
bool m_cache_doubletap_jump; bool m_cache_doubletap_jump;
bool m_cache_enable_clouds;
bool m_cache_enable_joysticks; bool m_cache_enable_joysticks;
bool m_cache_enable_particles;
bool m_cache_enable_fog; bool m_cache_enable_fog;
bool m_cache_enable_noclip; bool m_cache_enable_noclip;
bool m_cache_enable_free_move; bool m_cache_enable_free_move;
@ -828,16 +829,10 @@ Game::Game() :
{ {
g_settings->registerChangedCallback("chat_log_level", g_settings->registerChangedCallback("chat_log_level",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("disable_escape_sequences",
&settingChangedCallback, this);
g_settings->registerChangedCallback("doubletap_jump", g_settings->registerChangedCallback("doubletap_jump",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("enable_clouds",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_joysticks", g_settings->registerChangedCallback("enable_joysticks",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("enable_particles",
&settingChangedCallback, this);
g_settings->registerChangedCallback("enable_fog", g_settings->registerChangedCallback("enable_fog",
&settingChangedCallback, this); &settingChangedCallback, this);
g_settings->registerChangedCallback("mouse_sensitivity", g_settings->registerChangedCallback("mouse_sensitivity",
@ -937,6 +932,10 @@ bool Game::startup(bool *kill,
runData.time_from_last_punch = 10.0; runData.time_from_last_punch = 10.0;
m_game_ui->initFlags(); m_game_ui->initFlags();
if (g_settings->getBool("show_debug")) {
m_flags.debug_state = 1;
m_game_ui->m_flags.show_minimal_debug = true;
}
m_first_loop_after_window_activation = true; m_first_loop_after_window_activation = true;
@ -1175,7 +1174,7 @@ bool Game::init(
bool Game::initSound() bool Game::initSound()
{ {
#if USE_SOUND #if USE_SOUND
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) { if (g_sound_manager_singleton.get()) {
infostream << "Attempting to use OpenAL audio" << std::endl; infostream << "Attempting to use OpenAL audio" << std::endl;
sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
std::make_unique<SoundFallbackPathProvider>()); std::make_unique<SoundFallbackPathProvider>());
@ -1333,8 +1332,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Clouds /* Clouds
*/ */
if (m_cache_enable_clouds) clouds = make_irr<Clouds>(smgr, shader_src, -1, myrand());
clouds = make_irr<Clouds>(smgr, shader_src, -1, rand());
/* Skybox /* Skybox
*/ */
@ -1708,6 +1706,7 @@ void Game::updateDebugState()
hud->disableBlockBounds(); hud->disableBlockBounds();
if (!has_debug) { if (!has_debug) {
draw_control->show_wireframe = false; draw_control->show_wireframe = false;
smgr->setGlobalDebugData(0, bbox_debug_flag);
m_flags.disable_camera_update = false; m_flags.disable_camera_update = false;
m_game_formspec.disableDebugView(); m_game_formspec.disableDebugView();
} }
@ -1845,7 +1844,9 @@ void Game::processUserInput(f32 dtime)
m_game_focused = true; m_game_focused = true;
} }
if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()) { if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()
&& !gui_chat_console->isMyChild(guienv->getFocus()))
{
gui_chat_console->closeConsoleAtOnce(); gui_chat_console->closeConsoleAtOnce();
} }
@ -1909,34 +1910,22 @@ void Game::processKeyInput()
toggleNoClip(); toggleNoClip();
#if USE_SOUND #if USE_SOUND
} else if (wasKeyDown(KeyType::MUTE)) { } else if (wasKeyDown(KeyType::MUTE)) {
if (g_settings->getBool("enable_sound")) { bool new_mute_sound = !g_settings->getBool("mute_sound");
bool new_mute_sound = !g_settings->getBool("mute_sound"); g_settings->setBool("mute_sound", new_mute_sound);
g_settings->setBool("mute_sound", new_mute_sound); if (new_mute_sound)
if (new_mute_sound) m_game_ui->showTranslatedStatusText("Sound muted");
m_game_ui->showTranslatedStatusText("Sound muted"); else
else m_game_ui->showTranslatedStatusText("Sound unmuted");
m_game_ui->showTranslatedStatusText("Sound unmuted");
} else {
m_game_ui->showTranslatedStatusText("Sound system is disabled");
}
} else if (wasKeyDown(KeyType::INC_VOLUME)) { } else if (wasKeyDown(KeyType::INC_VOLUME)) {
if (g_settings->getBool("enable_sound")) { float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f;
float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f; g_settings->setFloat("sound_volume", new_volume);
g_settings->setFloat("sound_volume", new_volume); std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100)); m_game_ui->showStatusText(msg);
m_game_ui->showStatusText(msg);
} else {
m_game_ui->showTranslatedStatusText("Sound system is disabled");
}
} else if (wasKeyDown(KeyType::DEC_VOLUME)) { } else if (wasKeyDown(KeyType::DEC_VOLUME)) {
if (g_settings->getBool("enable_sound")) { float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f;
float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f; g_settings->setFloat("sound_volume", new_volume);
g_settings->setFloat("sound_volume", new_volume); std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100)); m_game_ui->showStatusText(msg);
m_game_ui->showStatusText(msg);
} else {
m_game_ui->showTranslatedStatusText("Sound system is disabled");
}
#else #else
} else if (wasKeyDown(KeyType::MUTE) || wasKeyDown(KeyType::INC_VOLUME) } else if (wasKeyDown(KeyType::MUTE) || wasKeyDown(KeyType::INC_VOLUME)
|| wasKeyDown(KeyType::DEC_VOLUME)) { || wasKeyDown(KeyType::DEC_VOLUME)) {
@ -2267,45 +2256,44 @@ void Game::toggleDebug()
LocalPlayer *player = client->getEnv().getLocalPlayer(); LocalPlayer *player = client->getEnv().getLocalPlayer();
bool has_debug = client->checkPrivilege("debug"); bool has_debug = client->checkPrivilege("debug");
bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG); bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
// Initial: No debug info // Initial: No debug info
// 1x toggle: Debug text // 1x toggle: Debug text
// 2x toggle: Debug text with profiler graph // 2x toggle: Debug text with profiler graph
// 3x toggle: Debug text and wireframe (needs "debug" priv) // 3x toggle: Debug text and wireframe (needs "debug" priv)
// Next toggle: Back to initial // 4x toggle: Debug text and bbox (needs "debug" priv)
// //
// The debug text can be in 2 modes: minimal and basic. // The debug text can be in 2 modes: minimal and basic.
// * Minimal: Only technical client info that not gameplay-relevant // * Minimal: Only technical client info that not gameplay-relevant
// * Basic: Info that might give gameplay advantage, e.g. pos, angle // * Basic: Info that might give gameplay advantage, e.g. pos, angle
// Basic mode is used when player has the debug HUD flag set, // Basic mode is used when player has the debug HUD flag set,
// otherwise the Minimal mode is used. // otherwise the Minimal mode is used.
if (!m_game_ui->m_flags.show_minimal_debug) {
m_game_ui->m_flags.show_minimal_debug = true; auto &state = m_flags.debug_state;
if (has_basic_debug) state = (state + 1) % 5;
m_game_ui->m_flags.show_basic_debug = true; if (state >= 3 && !has_debug)
m_game_ui->m_flags.show_profiler_graph = false; state = 0;
draw_control->show_wireframe = false;
m_game_ui->m_flags.show_minimal_debug = state > 0;
m_game_ui->m_flags.show_basic_debug = state > 0 && has_basic_debug;
m_game_ui->m_flags.show_profiler_graph = state == 2;
draw_control->show_wireframe = state == 3;
smgr->setGlobalDebugData(state == 4 ? bbox_debug_flag : 0,
state == 4 ? 0 : bbox_debug_flag);
if (state == 1) {
m_game_ui->showTranslatedStatusText("Debug info shown"); m_game_ui->showTranslatedStatusText("Debug info shown");
} else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) { } else if (state == 2) {
if (has_basic_debug)
m_game_ui->m_flags.show_basic_debug = true;
m_game_ui->m_flags.show_profiler_graph = true;
m_game_ui->showTranslatedStatusText("Profiler graph shown"); m_game_ui->showTranslatedStatusText("Profiler graph shown");
} else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) { } else if (state == 3) {
if (has_basic_debug) if (driver->getDriverType() == video::EDT_OGLES2)
m_game_ui->m_flags.show_basic_debug = true; m_game_ui->showTranslatedStatusText("Wireframe not supported by video driver");
m_game_ui->m_flags.show_profiler_graph = false; else
draw_control->show_wireframe = true; m_game_ui->showTranslatedStatusText("Wireframe shown");
m_game_ui->showTranslatedStatusText("Wireframe shown"); } else if (state == 4) {
m_game_ui->showTranslatedStatusText("Bounding boxes shown");
} else { } else {
m_game_ui->m_flags.show_minimal_debug = false; m_game_ui->showTranslatedStatusText("All debug info hidden");
m_game_ui->m_flags.show_basic_debug = false;
m_game_ui->m_flags.show_profiler_graph = false;
draw_control->show_wireframe = false;
if (has_debug) {
m_game_ui->showTranslatedStatusText("Debug info, profiler graph, and wireframe hidden");
} else {
m_game_ui->showTranslatedStatusText("Debug info and profiler graph hidden");
}
} }
} }
@ -2896,9 +2884,6 @@ void Game::handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam) void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam)
{ {
if (!clouds)
return;
clouds->setDensity(event->cloud_params.density); clouds->setDensity(event->cloud_params.density);
clouds->setColorBright(video::SColor(event->cloud_params.color_bright)); clouds->setColorBright(video::SColor(event->cloud_params.color_bright));
clouds->setColorAmbient(video::SColor(event->cloud_params.color_ambient)); clouds->setColorAmbient(video::SColor(event->cloud_params.color_ambient));
@ -2935,10 +2920,7 @@ void Game::updateChat(f32 dtime)
std::vector<LogEntry> entries = m_chat_log_buf.take(); std::vector<LogEntry> entries = m_chat_log_buf.take();
for (const auto& entry : entries) { for (const auto& entry : entries) {
std::string line; std::string line;
if (!m_cache_disable_escape_sequences) { line.append(color_for(entry.level)).append(entry.combined);
line.append(color_for(entry.level));
}
line.append(entry.combined);
chat_backend->addMessage(L"", utf8_to_wide(line)); chat_backend->addMessage(L"", utf8_to_wide(line));
} }
@ -3023,8 +3005,7 @@ void Game::updateCamera(f32 dtime)
client->updateCameraOffset(camera_offset); client->updateCameraOffset(camera_offset);
client->getEnv().updateCameraOffset(camera_offset); client->getEnv().updateCameraOffset(camera_offset);
if (clouds) clouds->updateCameraOffset(camera_offset);
clouds->updateCameraOffset(camera_offset);
} }
} }
} }
@ -3683,10 +3664,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
} else { } else {
runData.dig_time_complete = params.time; runData.dig_time_complete = params.time;
if (m_cache_enable_particles) { client->getParticleManager()->addNodeParticle(client,
client->getParticleManager()->addNodeParticle(client, player, nodepos, n, features);
player, nodepos, n, features);
}
} }
if (!runData.digging) { if (!runData.digging) {
@ -3771,11 +3750,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
client->interact(INTERACT_DIGGING_COMPLETED, pointed); client->interact(INTERACT_DIGGING_COMPLETED, pointed);
if (m_cache_enable_particles) { client->getParticleManager()->addDiggingParticles(client,
client->getParticleManager()->addDiggingParticles(client, player, nodepos, n, features);
player, nodepos, n, features);
}
// Send event to trigger sound // Send event to trigger sound
client->getEventManager()->put(new NodeDugEvent(nodepos, n)); client->getEventManager()->put(new NodeDugEvent(nodepos, n));
@ -3866,8 +3842,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
/* /*
Update clouds Update clouds
*/ */
if (clouds) updateClouds(dtime);
updateClouds(dtime);
/* /*
Update particles Update particles
@ -4129,11 +4104,8 @@ void Game::readSettings()
} }
m_chat_log_buf.setLogLevel(chat_log_level); m_chat_log_buf.setLogLevel(chat_log_level);
m_cache_disable_escape_sequences = g_settings->getBool("disable_escape_sequences");
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump"); m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
m_cache_enable_clouds = g_settings->getBool("enable_clouds");
m_cache_enable_joysticks = g_settings->getBool("enable_joysticks"); m_cache_enable_joysticks = g_settings->getBool("enable_joysticks");
m_cache_enable_particles = g_settings->getBool("enable_particles");
m_cache_enable_fog = g_settings->getBool("enable_fog"); m_cache_enable_fog = g_settings->getBool("enable_fog");
m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity", 0.001f, 10.0f); m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity", 0.001f, 10.0f);
m_cache_joystick_frustum_sensitivity = std::max(g_settings->getFloat("joystick_frustum_sensitivity"), 0.001f); m_cache_joystick_frustum_sensitivity = std::max(g_settings->getFloat("joystick_frustum_sensitivity"), 0.001f);

View file

@ -333,12 +333,11 @@ void GameFormSpec::showPauseMenu()
#ifndef __ANDROID__ #ifndef __ANDROID__
#if USE_SOUND #if USE_SOUND
if (g_settings->getBool("enable_sound")) { os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;" << strgettext("Sound Volume") << "]";
<< strgettext("Sound Volume") << "]";
}
#endif #endif
#endif #endif
if (g_touchcontrols) { if (g_touchcontrols) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;" os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;"
<< strgettext("Touchscreen Layout") << "]"; << strgettext("Touchscreen Layout") << "]";

View file

@ -215,7 +215,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
void GameUI::initFlags() void GameUI::initFlags()
{ {
m_flags = GameUI::Flags(); m_flags = GameUI::Flags();
m_flags.show_minimal_debug = g_settings->getBool("show_debug");
} }
void GameUI::showTranslatedStatusText(const char *str) void GameUI::showTranslatedStatusText(const char *str)

View file

@ -94,8 +94,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
auto it_img = g_imgCache.find(origname); auto it_img = g_imgCache.find(origname);
video::IImage *srcimg = (it_img != g_imgCache.end()) ? it_img->second : nullptr; video::IImage *srcimg = (it_img != g_imgCache.end()) ? it_img->second : nullptr;
if (!srcimg) { if (!srcimg) {
if (!g_settings->getBool("gui_scaling_filter_txr2img")) // Download image from GPU
return src;
srcimg = driver->createImageFromData(src->getColorFormat(), srcimg = driver->createImageFromData(src->getColorFormat(),
src->getSize(), src->lock(video::ETLM_READ_ONLY), false); src->getSize(), src->lock(video::ETLM_READ_ONLY), false);
src->unlock(); src->unlock();

View file

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include "irr_v2d.h"
#include "joystick_controller.h" #include "joystick_controller.h"
#include <list> #include <list>
#include "keycode.h" #include "keycode.h"

View file

@ -4,7 +4,9 @@
#pragma once #pragma once
#include "irrlichttypes_extrabloated.h" #include <IEventReceiver.h>
#include "irrlichttypes.h"
#include "keys.h" #include "keys.h"
#include <bitset> #include <bitset>
#include <vector> #include <vector>

View file

@ -26,10 +26,14 @@
MeshMakeData MeshMakeData
*/ */
MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length): MeshMakeData::MeshMakeData(const NodeDefManager *ndef,
side_length(side_length), u16 side_length, MeshGrid mesh_grid) :
nodedef(ndef) m_side_length(side_length),
{} m_mesh_grid(mesh_grid),
m_nodedef(ndef)
{
assert(m_side_length > 0);
}
void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos) void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
{ {
@ -38,8 +42,9 @@ void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE; v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
m_vmanip.clear(); m_vmanip.clear();
// extra 1 block thick layer around the mesh
VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE, VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
blockpos_nodes + v3s16(1,1,1) * (side_length + MAP_BLOCKSIZE /* extra layer of blocks around the mesh */) - v3s16(1,1,1)); blockpos_nodes + v3s16(1,1,1) * (m_side_length + MAP_BLOCKSIZE) - v3s16(1,1,1));
m_vmanip.addArea(voxel_area); m_vmanip.addArea(voxel_area);
} }
@ -52,17 +57,30 @@ void MeshMakeData::fillBlockData(const v3s16 &bp, MapNode *data)
m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size); m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
} }
void MeshMakeData::fillSingleNode(MapNode data, MapNode padding)
{
m_blockpos = {0, 0, 0};
m_vmanip.clear();
// area around 0,0,0 so that this positon has neighbors
const s16 sz = 3;
m_vmanip.addArea({v3s16(-sz), v3s16(sz)});
u32 count = m_vmanip.m_area.getVolume();
for (u32 i = 0; i < count; i++) {
m_vmanip.m_data[i] = padding;
m_vmanip.m_flags[i] &= ~VOXELFLAG_NO_DATA;
}
m_vmanip.setNodeNoEmerge({0, 0, 0}, data);
}
void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos) void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
{ {
if (crack_level >= 0) if (crack_level >= 0)
m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE; m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
} }
void MeshMakeData::setSmoothLighting(bool smooth_lighting)
{
m_smooth_lighting = smooth_lighting;
}
/* /*
Light and vertex color functions Light and vertex color functions
*/ */
@ -133,7 +151,7 @@ u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef)
static u16 getSmoothLightCombined(const v3s16 &p, static u16 getSmoothLightCombined(const v3s16 &p,
const std::array<v3s16,8> &dirs, MeshMakeData *data) const std::array<v3s16,8> &dirs, MeshMakeData *data)
{ {
const NodeDefManager *ndef = data->nodedef; const NodeDefManager *ndef = data->m_nodedef;
u16 ambient_occlusion = 0; u16 ambient_occlusion = 0;
u16 light_count = 0; u16 light_count = 0;
@ -321,7 +339,7 @@ void final_color_blend(video::SColor *result,
*/ */
void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, TileSpec &tile) void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
{ {
const NodeDefManager *ndef = data->nodedef; const NodeDefManager *ndef = data->m_nodedef;
const ContentFeatures &f = ndef->get(mn); const ContentFeatures &f = ndef->get(mn);
tile = f.tiles[tileindex]; tile = f.tiles[tileindex];
bool has_crack = p == data->m_crack_pos_relative; bool has_crack = p == data->m_crack_pos_relative;
@ -341,7 +359,7 @@ void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data,
*/ */
void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *data, TileSpec &tile) void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *data, TileSpec &tile)
{ {
const NodeDefManager *ndef = data->nodedef; const NodeDefManager *ndef = data->m_nodedef;
// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0), // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
// (0,0,1), (0,0,-1) or (0,0,0) // (0,0,1), (0,0,-1) or (0,0,0)
@ -593,7 +611,7 @@ void PartialMeshBuffer::draw(video::IVideoDriver *driver) const
MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offset): MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offset):
m_tsrc(client->getTextureSource()), m_tsrc(client->getTextureSource()),
m_shdrsrc(client->getShaderSource()), m_shdrsrc(client->getShaderSource()),
m_bounding_sphere_center((data->side_length * 0.5f - 0.5f) * BS), m_bounding_sphere_center((data->m_side_length * 0.5f - 0.5f) * BS),
m_animation_force_timer(0), // force initial animation m_animation_force_timer(0), // force initial animation
m_last_crack(-1) m_last_crack(-1)
{ {
@ -602,10 +620,12 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
for (auto &m : m_mesh) for (auto &m : m_mesh)
m = make_irr<scene::SMesh>(); m = make_irr<scene::SMesh>();
auto mesh_grid = client->getMeshGrid(); auto mesh_grid = data->m_mesh_grid;
v3s16 bp = data->m_blockpos; v3s16 bp = data->m_blockpos;
// Only generate minimap mapblocks at even coordinates. // Only generate minimap mapblocks at grid aligned coordinates.
if (mesh_grid.isMeshPos(bp) && client->getMinimap()) { // FIXME: ^ doesn't really make sense. and in practice, bp is always aligned
if (mesh_grid.isMeshPos(bp) && data->m_generate_minimap) {
// meshgen area always fits into a grid cell
m_minimap_mapblocks.resize(mesh_grid.getCellVolume(), nullptr); m_minimap_mapblocks.resize(mesh_grid.getCellVolume(), nullptr);
v3s16 ofs; v3s16 ofs;
@ -622,17 +642,13 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
} }
} }
// algin vertices to mesh grid, not meshgen area
v3f offset = intToFloat((data->m_blockpos - mesh_grid.getMeshPos(data->m_blockpos)) * MAP_BLOCKSIZE, BS); v3f offset = intToFloat((data->m_blockpos - mesh_grid.getMeshPos(data->m_blockpos)) * MAP_BLOCKSIZE, BS);
MeshCollector collector(m_bounding_sphere_center, offset); MeshCollector collector(m_bounding_sphere_center, offset);
/*
Add special graphics:
- torches
- flowing water
- fences
- whatever
*/
{ {
// Generate everything
MapblockMeshGenerator(data, &collector).generate(); MapblockMeshGenerator(data, &collector).generate();
} }
@ -640,9 +656,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
Convert MeshCollector to SMesh Convert MeshCollector to SMesh
*/ */
const bool desync_animations = g_settings->getBool(
"desynchronize_mapblock_texture_animation");
m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq); m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq);
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) { for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
@ -679,16 +692,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
auto &info = m_animation_info[{layer, i}]; auto &info = m_animation_info[{layer, i}];
info.tile = p.layer; info.tile = p.layer;
info.frame = 0; info.frame = 0;
if (desync_animations) { info.frame_offset = 0;
// Get starting position from noise
info.frame_offset =
100000 * (2.0 + noise3d(
data->m_blockpos.X, data->m_blockpos.Y,
data->m_blockpos.Z, 0));
} else {
// Play all synchronized
info.frame_offset = 0;
}
// Replace tile texture with the first animation frame // Replace tile texture with the first animation frame
p.layer.texture = (*p.layer.frames)[0].texture; p.layer.texture = (*p.layer.frames)[0].texture;
} }
@ -702,6 +706,16 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
tex.MagFilter = video::ETMAGF_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST;
}); });
/*
* The second layer is for overlays, but uses the same vertex positions
* as the first, which quickly leads to z-fighting.
* To fix this we can offset the polygons in the direction of the camera.
* This only affects the depth buffer and leads to no visual gaps in geometry.
*/
if (layer == 1) {
material.PolygonOffsetSlopeScale = -1;
material.PolygonOffsetDepthBias = -1;
}
{ {
material.MaterialType = m_shdrsrc->getShaderInfo( material.MaterialType = m_shdrsrc->getShaderInfo(
@ -738,7 +752,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
} }
} }
m_bsp_tree.buildTree(&m_transparent_triangles, data->side_length); m_bsp_tree.buildTree(&m_transparent_triangles, data->m_side_length);
// Check if animation is required for this mesh // Check if animation is required for this mesh
m_has_animation = m_has_animation =
@ -947,21 +961,22 @@ video::SColor encode_light(u16 light, u8 emissive_light)
u8 get_solid_sides(MeshMakeData *data) u8 get_solid_sides(MeshMakeData *data)
{ {
std::unordered_map<v3s16, u8> results;
v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE; v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
const NodeDefManager *ndef = data->nodedef; const NodeDefManager *ndef = data->m_nodedef;
u8 result = 0x3F; // all sides solid; const u16 side = data->m_side_length;
assert(data->m_vmanip.m_area.contains(blockpos_nodes + v3s16(side - 1)));
for (s16 i = 0; i < data->side_length && result != 0; i++) u8 result = 0x3F; // all sides solid
for (s16 j = 0; j < data->side_length && result != 0; j++) { for (s16 i = 0; i < side && result != 0; i++)
for (s16 j = 0; j < side && result != 0; j++) {
v3s16 positions[6] = { v3s16 positions[6] = {
v3s16(0, i, j), v3s16(0, i, j),
v3s16(data->side_length - 1, i, j), v3s16(side - 1, i, j),
v3s16(i, 0, j), v3s16(i, 0, j),
v3s16(i, data->side_length - 1, j), v3s16(i, side - 1, j),
v3s16(i, j, 0), v3s16(i, j, 0),
v3s16(i, j, data->side_length - 1) v3s16(i, j, side - 1)
}; };
for (u8 k = 0; k < 6; k++) { for (u8 k = 0; k < 6; k++) {

View file

@ -4,8 +4,11 @@
#pragma once #pragma once
#include "irrlichttypes_extrabloated.h" #include "irrlichttypes.h"
#include "irr_ptr.h" #include "irr_ptr.h"
#include "IMesh.h"
#include "SMeshBuffer.h"
#include "util/numeric.h" #include "util/numeric.h"
#include "client/tile.h" #include "client/tile.h"
#include "voxel.h" #include "voxel.h"
@ -13,6 +16,10 @@
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
namespace irr::video {
class IVideoDriver;
}
class Client; class Client;
class NodeDefManager; class NodeDefManager;
class IShaderSource; class IShaderSource;
@ -29,14 +36,25 @@ struct MinimapMapblock;
struct MeshMakeData struct MeshMakeData
{ {
VoxelManipulator m_vmanip; VoxelManipulator m_vmanip;
// base pos of meshgen area, in blocks
v3s16 m_blockpos = v3s16(-1337,-1337,-1337); v3s16 m_blockpos = v3s16(-1337,-1337,-1337);
// size of meshgen area, in nodes.
// vmanip will have at least an extra 1 node onion layer.
// area is expected to fit into mesh grid cell.
u16 m_side_length;
// vertex positions will be relative to this grid
MeshGrid m_mesh_grid;
// relative to blockpos
v3s16 m_crack_pos_relative = v3s16(-1337,-1337,-1337); v3s16 m_crack_pos_relative = v3s16(-1337,-1337,-1337);
bool m_generate_minimap = false;
bool m_smooth_lighting = false; bool m_smooth_lighting = false;
u16 side_length; bool m_enable_water_reflections = false;
const NodeDefManager *nodedef; const NodeDefManager *m_nodedef;
MeshMakeData(const NodeDefManager *ndef, u16 side_length); MeshMakeData(const NodeDefManager *ndef, u16 side_lingth, MeshGrid mesh_grid);
/* /*
Copy block data manually (to allow optimizations by the caller) Copy block data manually (to allow optimizations by the caller)
@ -44,15 +62,15 @@ struct MeshMakeData
void fillBlockDataBegin(const v3s16 &blockpos); void fillBlockDataBegin(const v3s16 &blockpos);
void fillBlockData(const v3s16 &bp, MapNode *data); void fillBlockData(const v3s16 &bp, MapNode *data);
/*
Prepare block data for rendering a single node located at (0,0,0).
*/
void fillSingleNode(MapNode data, MapNode padding = MapNode(CONTENT_AIR));
/* /*
Set the (node) position of a crack Set the (node) position of a crack
*/ */
void setCrack(int crack_level, v3s16 crack_pos); void setCrack(int crack_level, v3s16 crack_pos);
/*
Enable or disable smooth lighting
*/
void setSmoothLighting(bool smooth_lighting);
}; };
// represents a triangle as indexes into the vertex buffer in SMeshBuffer // represents a triangle as indexes into the vertex buffer in SMeshBuffer

View file

@ -3,7 +3,6 @@
// Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com> // Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
#include "mesh.h" #include "mesh.h"
#include "S3DVertex.h"
#include "debug.h" #include "debug.h"
#include "log.h" #include "log.h"
#include <cmath> #include <cmath>
@ -11,6 +10,9 @@
#include <IAnimatedMesh.h> #include <IAnimatedMesh.h>
#include <SAnimatedMesh.h> #include <SAnimatedMesh.h>
#include <IAnimatedMeshSceneNode.h> #include <IAnimatedMeshSceneNode.h>
#include "S3DVertex.h"
#include "SMesh.h"
#include "SMeshBuffer.h"
inline static void applyShadeFactor(video::SColor& color, float factor) inline static void applyShadeFactor(video::SColor& color, float factor)
{ {

View file

@ -4,10 +4,20 @@
#pragma once #pragma once
#include "SColor.h"
#include "SMaterialLayer.h" #include "SMaterialLayer.h"
#include "irrlichttypes_extrabloated.h"
#include "nodedef.h" #include "nodedef.h"
namespace irr {
namespace scene {
class IAnimatedMesh;
class IMesh;
class IMeshBuffer;
}
}
using namespace irr;
/*! /*!
* Applies shading to a color based on the surface's * Applies shading to a color based on the surface's
* normal vector. * normal vector.

View file

@ -40,6 +40,7 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
m_client(client) m_client(client)
{ {
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting"); m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
m_cache_enable_water_reflections = g_settings->getBool("enable_water_reflections");
} }
MeshUpdateQueue::~MeshUpdateQueue() MeshUpdateQueue::~MeshUpdateQueue()
@ -176,7 +177,8 @@ void MeshUpdateQueue::done(v3s16 pos)
void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q) void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
{ {
auto mesh_grid = m_client->getMeshGrid(); auto mesh_grid = m_client->getMeshGrid();
MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size); MeshMakeData *data = new MeshMakeData(m_client->ndef(),
MAP_BLOCKSIZE * mesh_grid.cell_size, mesh_grid);
q->data = data; q->data = data;
data->fillBlockDataBegin(q->p); data->fillBlockDataBegin(q->p);
@ -191,7 +193,9 @@ void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
} }
data->setCrack(q->crack_level, q->crack_pos); data->setCrack(q->crack_level, q->crack_pos);
data->setSmoothLighting(m_cache_smooth_lighting); data->m_generate_minimap = !!m_client->getMinimap();
data->m_smooth_lighting = m_cache_smooth_lighting;
data->m_enable_water_reflections = m_cache_enable_water_reflections;
} }
/* /*

View file

@ -69,8 +69,9 @@ private:
std::unordered_set<v3s16> m_inflight_blocks; std::unordered_set<v3s16> m_inflight_blocks;
std::mutex m_mutex; std::mutex m_mutex;
// TODO: Add callback to update these when g_settings changes // TODO: Add callback to update these when g_settings changes, and update all meshes
bool m_cache_smooth_lighting; bool m_cache_smooth_lighting;
bool m_cache_enable_water_reflections;
void fillDataFromMapBlocks(QueuedMeshUpdate *q); void fillDataFromMapBlocks(QueuedMeshUpdate *q);
}; };

View file

@ -41,45 +41,6 @@ void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *verti
p.indices.push_back(indices[i] + vertex_count); p.indices.push_back(indices[i] + vertex_count);
} }
void MeshCollector::append(const TileSpec &tile, const video::S3DVertex *vertices,
u32 numVertices, const u16 *indices, u32 numIndices, v3f pos,
video::SColor c, u8 light_source)
{
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
const TileLayer *layer = &tile.layers[layernum];
if (layer->texture_id == 0)
continue;
append(*layer, vertices, numVertices, indices, numIndices, pos, c,
light_source, layernum, tile.world_aligned);
}
}
void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *vertices,
u32 numVertices, const u16 *indices, u32 numIndices, v3f pos,
video::SColor c, u8 light_source, u8 layernum, bool use_scale)
{
PreMeshBuffer &p = findBuffer(layer, layernum, numVertices);
f32 scale = 1.0f;
if (use_scale)
scale = 1.0f / layer.scale;
u32 vertex_count = p.vertices.size();
for (u32 i = 0; i < numVertices; i++) {
video::SColor color = c;
if (!light_source)
applyFacesShading(color, vertices[i].Normal);
auto vpos = vertices[i].Pos + pos + offset;
p.vertices.emplace_back(vpos, vertices[i].Normal, color,
scale * vertices[i].TCoords);
m_bounding_radius_sq = std::max(m_bounding_radius_sq,
(vpos - m_center_pos).getLengthSQ());
}
for (u32 i = 0; i < numIndices; i++)
p.indices.push_back(indices[i] + vertex_count);
}
PreMeshBuffer &MeshCollector::findBuffer( PreMeshBuffer &MeshCollector::findBuffer(
const TileLayer &layer, u8 layernum, u32 numVertices) const TileLayer &layer, u8 layernum, u32 numVertices)
{ {

View file

@ -35,21 +35,12 @@ struct MeshCollector
void append(const TileSpec &material, void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices, const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices); const u16 *indices, u32 numIndices);
void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
v3f pos, video::SColor c, u8 light_source);
private: private:
void append(const TileLayer &material, void append(const TileLayer &material,
const video::S3DVertex *vertices, u32 numVertices, const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices, const u16 *indices, u32 numIndices,
u8 layernum, bool use_scale = false); u8 layernum, bool use_scale = false);
void append(const TileLayer &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
v3f pos, video::SColor c, u8 light_source,
u8 layernum, bool use_scale = false);
PreMeshBuffer &findBuffer(const TileLayer &layer, u8 layernum, u32 numVertices); PreMeshBuffer &findBuffer(const TileLayer &layer, u8 layernum, u32 numVertices);
}; };

View file

@ -4,18 +4,35 @@
#pragma once #pragma once
#include "../hud.h" #include "irrlichttypes.h"
#include "irrlichttypes_extrabloated.h"
#include "irr_ptr.h" #include "irr_ptr.h"
#include "rect.h"
#include "SMeshBuffer.h"
#include "../hud.h"
#include "mapnode.h"
#include "util/thread.h" #include "util/thread.h"
#include "voxel.h"
#include <map> #include <map>
#include <string> #include <string>
#include <vector> #include <vector>
namespace irr {
namespace video {
class IVideoDriver;
class IImage;
class ITexture;
}
namespace scene {
class ISceneNode;
}
}
class Client; class Client;
class NodeDefManager;
class ITextureSource; class ITextureSource;
class IShaderSource; class IShaderSource;
class VoxelManipulator;
#define MINIMAP_MAX_SX 512 #define MINIMAP_MAX_SX 512
#define MINIMAP_MAX_SY 512 #define MINIMAP_MAX_SY 512

View file

@ -22,6 +22,8 @@
#include "settings.h" #include "settings.h"
#include "profiler.h" #include "profiler.h"
#include "SMeshBuffer.h"
using BlendMode = ParticleParamTypes::BlendMode; using BlendMode = ParticleParamTypes::BlendMode;
ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc) ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc)

View file

@ -4,12 +4,21 @@
#pragma once #pragma once
#include "irrlichttypes_bloated.h"
#include "irr_ptr.h"
#include "ISceneNode.h"
#include "S3DVertex.h"
#include "SMeshBuffer.h"
#include <mutex>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include "irrlichttypes_extrabloated.h"
#include "irr_ptr.h"
#include "../particles.h" #include "../particles.h"
namespace irr::video {
class ITexture;
}
struct ClientEvent; struct ClientEvent;
class ParticleManager; class ParticleManager;
class ClientEnvironment; class ClientEnvironment;

View file

@ -18,7 +18,7 @@ void SetColorMaskStep::run(PipelineContext &context)
{ {
video::SOverrideMaterial &mat = context.device->getVideoDriver()->getOverrideMaterial(); video::SOverrideMaterial &mat = context.device->getVideoDriver()->getOverrideMaterial();
mat.reset(); mat.reset();
mat.Material.ColorMask = color_mask; mat.Material.ColorMask = static_cast<video::E_COLOR_PLANE>(color_mask);
mat.EnableProps = video::EMP_COLOR_MASK; mat.EnableProps = video::EMP_COLOR_MASK;
mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID | mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID |
scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT; scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT;

View file

@ -21,7 +21,7 @@ PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_t
void PostProcessingStep::configureMaterial() void PostProcessingStep::configureMaterial()
{ {
material.UseMipMaps = false; material.UseMipMaps = false;
material.ZBuffer = true; material.ZBuffer = video::ECFN_LESSEQUAL;
material.ZWriteEnable = video::EZW_ON; material.ZWriteEnable = video::EZW_ON;
for (u32 k = 0; k < texture_map.size(); ++k) { for (u32 k = 0; k < texture_map.size(); ++k) {
material.TextureLayers[k].AnisotropicFilter = 0; material.TextureLayers[k].AnisotropicFilter = 0;
@ -196,7 +196,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
} }
if (enable_volumetric_light) { if (enable_volumetric_light) {
buffer->setTexture(TEXTURE_VOLUME, scale, "volume", color_format); buffer->setTexture(TEXTURE_VOLUME, scale, "volume", bloom_format);
shader_id = client->getShaderSource()->getShaderRaw("volumetric_light"); shader_id = client->getShaderSource()->getShaderRaw("volumetric_light");
auto volume = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_DEPTH }); auto volume = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_DEPTH });

View file

@ -50,8 +50,7 @@ void FpsControl::limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused)
if (busy_time < frametime_min) { if (busy_time < frametime_min) {
sleep_time = frametime_min - busy_time; sleep_time = frametime_min - busy_time;
if (sleep_time > 0) porting::preciseSleepUs(sleep_time);
sleep_us(sleep_time);
} else { } else {
sleep_time = 0; sleep_time = 0;
} }

View file

@ -687,13 +687,23 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT: case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE: case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
case TILE_MATERIAL_WAVING_LIQUID_BASIC: case TILE_MATERIAL_WAVING_LIQUID_BASIC:
case TILE_MATERIAL_LIQUID_TRANSPARENT:
shaders_header << "#define MATERIAL_WAVING_LIQUID 1\n"; shaders_header << "#define MATERIAL_WAVING_LIQUID 1\n";
break; break;
default: default:
shaders_header << "#define MATERIAL_WAVING_LIQUID 0\n"; shaders_header << "#define MATERIAL_WAVING_LIQUID 0\n";
break; break;
} }
switch (material_type) {
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
case TILE_MATERIAL_LIQUID_TRANSPARENT:
shaders_header << "#define MATERIAL_WATER_REFLECTIONS 1\n";
break;
default:
shaders_header << "#define MATERIAL_WATER_REFLECTIONS 0\n";
break;
}
shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n"; shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n"; shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";

View file

@ -13,18 +13,6 @@
using m4f = core::matrix4; using m4f = core::matrix4;
static v3f quantizeDirection(v3f direction, float step)
{
float yaw = std::atan2(direction.Z, direction.X);
float pitch = std::asin(direction.Y); // assume look is normalized
yaw = std::floor(yaw / step) * step;
pitch = std::floor(pitch / step) * step;
return v3f(std::cos(yaw)*std::cos(pitch), std::sin(pitch), std::sin(yaw)*std::cos(pitch));
}
void DirectionalLight::createSplitMatrices(const Camera *cam) void DirectionalLight::createSplitMatrices(const Camera *cam)
{ {
static const float COS_15_DEG = 0.965926f; static const float COS_15_DEG = 0.965926f;
@ -74,7 +62,7 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
v3f boundVec = (cam_pos_scene + farCorner * sfFar) - center_scene; v3f boundVec = (cam_pos_scene + farCorner * sfFar) - center_scene;
float radius = boundVec.getLength(); float radius = boundVec.getLength();
float length = radius * 3.0f; float length = radius * 3.0f;
v3f eye_displacement = quantizeDirection(direction, M_PI / 2880 /*15 seconds*/) * length; v3f eye_displacement = direction * length;
// we must compute the viewmat with the position - the camera offset // we must compute the viewmat with the position - the camera offset
// but the future_frustum position must be the actual world position // but the future_frustum position must be the actual world position

View file

@ -27,7 +27,7 @@ static video::SMaterial baseMaterial()
video::SMaterial mat; video::SMaterial mat;
mat.ZBuffer = video::ECFN_DISABLED; mat.ZBuffer = video::ECFN_DISABLED;
mat.ZWriteEnable = video::EZW_OFF; mat.ZWriteEnable = video::EZW_OFF;
mat.AntiAliasing = 0; mat.AntiAliasing = video::EAAM_OFF;
mat.TextureLayers[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE; mat.TextureLayers[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
mat.TextureLayers[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; mat.TextureLayers[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
mat.BackfaceCulling = false; mat.BackfaceCulling = false;

View file

@ -50,6 +50,11 @@ struct FrameSpec
video::ITexture *texture = nullptr; video::ITexture *texture = nullptr;
}; };
/**
* We have two tile layers:
* layer 0 = base
* layer 1 = overlay
*/
#define MAX_TILE_LAYERS 2 #define MAX_TILE_LAYERS 2
//! Defines a layer of a tile. //! Defines a layer of a tile.

View file

@ -21,8 +21,8 @@
#include <IMeshManipulator.h> #include <IMeshManipulator.h>
#include "client/renderingengine.h" #include "client/renderingengine.h"
#define WIELD_SCALE_FACTOR 30.0 #define WIELD_SCALE_FACTOR 30.0f
#define WIELD_SCALE_FACTOR_EXTRUDED 40.0 #define WIELD_SCALE_FACTOR_EXTRUDED 40.0f
#define MIN_EXTRUSION_MESH_RESOLUTION 16 #define MIN_EXTRUSION_MESH_RESOLUTION 16
#define MAX_EXTRUSION_MESH_RESOLUTION 512 #define MAX_EXTRUSION_MESH_RESOLUTION 512
@ -225,18 +225,6 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
g_extrusion_mesh_cache = nullptr; g_extrusion_mesh_cache = nullptr;
} }
void WieldMeshSceneNode::setCube(const ContentFeatures &f,
v3f wield_scale)
{
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
scene::SMesh *copy = cloneMesh(cubemesh);
cubemesh->drop();
postProcessNodeMesh(copy, f, false, &m_material_type, &m_colors, true);
changeToMesh(copy);
copy->drop();
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
}
void WieldMeshSceneNode::setExtruded(const std::string &imagename, void WieldMeshSceneNode::setExtruded(const std::string &imagename,
const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc, const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc,
u8 num_frames) u8 num_frames)
@ -251,6 +239,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
core::dimension2d<u32> dim = texture->getSize(); core::dimension2d<u32> dim = texture->getSize();
// Detect animation texture and pull off top frame instead of using entire thing // Detect animation texture and pull off top frame instead of using entire thing
// FIXME: this is quite unportable, we should be working with the original TileLayer if there's one
if (num_frames > 1) { if (num_frames > 1) {
u32 frame_height = dim.Height / num_frames; u32 frame_height = dim.Height / num_frames;
dim = core::dimension2d<u32>(dim.Width, frame_height); dim = core::dimension2d<u32>(dim.Width, frame_height);
@ -262,11 +251,13 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
mesh->getMeshBuffer(0)->getMaterial().setTexture(0, mesh->getMeshBuffer(0)->getMaterial().setTexture(0,
tsrc->getTexture(imagename)); tsrc->getTexture(imagename));
if (overlay_texture) { if (overlay_texture) {
// duplicate the extruded mesh for the overlay
scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0)); scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0));
copy->getMaterial().setTexture(0, overlay_texture); copy->getMaterial().setTexture(0, overlay_texture);
mesh->addMeshBuffer(copy); mesh->addMeshBuffer(copy);
copy->drop(); copy->drop();
} }
mesh->recalculateBoundingBox();
changeToMesh(mesh); changeToMesh(mesh);
mesh->drop(); mesh->drop();
@ -292,14 +283,10 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
} }
} }
static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, static scene::SMesh *createGenericNodeMesh(Client *client, MapNode n,
std::vector<ItemPartColor> *colors, const ContentFeatures &f) std::vector<ItemPartColor> *colors, const ContentFeatures &f)
{ {
MeshMakeData mesh_make_data(client->ndef(), 1); n.setParam1(0xff);
MeshCollector collector(v3f(0.0f * BS), v3f());
mesh_make_data.setSmoothLighting(false);
MapblockMeshGenerator gen(&mesh_make_data, &collector);
if (n.getParam2()) { if (n.getParam2()) {
// keep it // keep it
} else if (f.param_type_2 == CPT2_WALLMOUNTED || } else if (f.param_type_2 == CPT2_WALLMOUNTED ||
@ -313,29 +300,43 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
} else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) { } else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) {
n.setParam2(1); n.setParam2(1);
} }
gen.renderSingle(n.getContent(), n.getParam2());
MeshCollector collector(v3f(0), v3f());
{
MeshMakeData mmd(client->ndef(), 1, MeshGrid{1});
mmd.fillSingleNode(n);
MapblockMeshGenerator(&mmd, &collector).generate();
}
colors->clear(); colors->clear();
scene::SMesh *mesh = new scene::SMesh(); scene::SMesh *mesh = new scene::SMesh();
for (auto &prebuffers : collector.prebuffers) for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
auto &prebuffers = collector.prebuffers[layer];
for (PreMeshBuffer &p : prebuffers) { for (PreMeshBuffer &p : prebuffers) {
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) { if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
const FrameSpec &frame = (*p.layer.frames)[0]; const FrameSpec &frame = (*p.layer.frames)[0];
p.layer.texture = frame.texture; p.layer.texture = frame.texture;
} }
for (video::S3DVertex &v : p.vertices) { for (video::S3DVertex &v : p.vertices)
v.Color.setAlpha(255); v.Color.setAlpha(255);
}
scene::SMeshBuffer *buf = new scene::SMeshBuffer(); auto buf = make_irr<scene::SMeshBuffer>();
buf->Material.setTexture(0, p.layer.texture);
p.layer.applyMaterialOptions(buf->Material);
mesh->addMeshBuffer(buf);
buf->append(&p.vertices[0], p.vertices.size(), buf->append(&p.vertices[0], p.vertices.size(),
&p.indices[0], p.indices.size()); &p.indices[0], p.indices.size());
buf->drop();
colors->push_back( // Set up material
ItemPartColor(p.layer.has_color, p.layer.color)); buf->Material.setTexture(0, p.layer.texture);
if (layer == 1) {
buf->Material.PolygonOffsetSlopeScale = -1;
buf->Material.PolygonOffsetDepthBias = -1;
}
p.layer.applyMaterialOptions(buf->Material);
mesh->addMeshBuffer(buf.get());
colors->emplace_back(p.layer.has_color, p.layer.color);
} }
}
mesh->recalculateBoundingBox();
return mesh; return mesh;
} }
@ -375,15 +376,12 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
} }
// Handle nodes // Handle nodes
// See also CItemDefManager::createClientCached()
if (def.type == ITEM_NODE) { if (def.type == ITEM_NODE) {
bool cull_backface = f.needsBackfaceCulling();
// Select rendering method
switch (f.drawtype) { switch (f.drawtype) {
case NDT_AIRLIKE: case NDT_AIRLIKE:
setExtruded("no_texture_airlike.png", "", setExtruded("no_texture_airlike.png", "",
v3f(1.0, 1.0, 1.0), tsrc, 1); v3f(1), tsrc, 1);
break; break;
case NDT_SIGNLIKE: case NDT_SIGNLIKE:
case NDT_TORCHLIKE: case NDT_TORCHLIKE:
@ -393,38 +391,33 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
v3f wscale = wield_scale; v3f wscale = wield_scale;
if (f.drawtype == NDT_FLOWINGLIQUID) if (f.drawtype == NDT_FLOWINGLIQUID)
wscale.Z *= 0.1f; wscale.Z *= 0.1f;
setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
tsrc->getTextureName(f.tiles[0].layers[1].texture_id),
wscale, tsrc,
f.tiles[0].layers[0].animation_frame_count);
// Add color
const TileLayer &l0 = f.tiles[0].layers[0]; const TileLayer &l0 = f.tiles[0].layers[0];
m_colors.emplace_back(l0.has_color, l0.color);
const TileLayer &l1 = f.tiles[0].layers[1]; const TileLayer &l1 = f.tiles[0].layers[1];
setExtruded(tsrc->getTextureName(l0.texture_id),
tsrc->getTextureName(l1.texture_id),
wscale, tsrc,
l0.animation_frame_count);
// Add color
m_colors.emplace_back(l0.has_color, l0.color);
m_colors.emplace_back(l1.has_color, l1.color); m_colors.emplace_back(l1.has_color, l1.color);
break; break;
} }
case NDT_PLANTLIKE_ROOTED: { case NDT_PLANTLIKE_ROOTED: {
setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), // use the plant tile
"", wield_scale, tsrc,
f.special_tiles[0].layers[0].animation_frame_count);
// Add color
const TileLayer &l0 = f.special_tiles[0].layers[0]; const TileLayer &l0 = f.special_tiles[0].layers[0];
setExtruded(tsrc->getTextureName(l0.texture_id),
"", wield_scale, tsrc,
l0.animation_frame_count);
m_colors.emplace_back(l0.has_color, l0.color); m_colors.emplace_back(l0.has_color, l0.color);
break; break;
} }
case NDT_NORMAL:
case NDT_ALLFACES:
case NDT_LIQUID:
setCube(f, wield_scale);
break;
default: { default: {
// Render non-trivial drawtypes like the actual node // Render all other drawtypes like the actual node
MapNode n(id); MapNode n(id);
if (def.place_param2) if (def.place_param2)
n.setParam2(*def.place_param2); n.setParam2(*def.place_param2);
mesh = createSpecialNodeMesh(client, n, &m_colors, f); mesh = createGenericNodeMesh(client, n, &m_colors, f);
changeToMesh(mesh); changeToMesh(mesh);
mesh->drop(); mesh->drop();
m_meshnode->setScale( m_meshnode->setScale(
@ -437,9 +430,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
u32 material_count = m_meshnode->getMaterialCount(); u32 material_count = m_meshnode->getMaterialCount();
for (u32 i = 0; i < material_count; ++i) { for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i); video::SMaterial &material = m_meshnode->getMaterial(i);
// FIXME: overriding this breaks different alpha modes the mesh may have
material.MaterialType = m_material_type; material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f; material.MaterialTypeParam = 0.5f;
material.BackfaceCulling = cull_backface;
material.forEachTexture([this] (auto &tex) { material.forEachTexture([this] (auto &tex) {
setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter, setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter,
m_anisotropic_filter); m_anisotropic_filter);
@ -550,8 +543,6 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
// Shading is on by default // Shading is on by default
result->needs_shading = true; result->needs_shading = true;
bool cull_backface = f.needsBackfaceCulling();
// If inventory_image is defined, it overrides everything else // If inventory_image is defined, it overrides everything else
const std::string inventory_image = item.getInventoryImage(idef); const std::string inventory_image = item.getInventoryImage(idef);
const std::string inventory_overlay = item.getInventoryOverlay(idef); const std::string inventory_overlay = item.getInventoryOverlay(idef);
@ -568,51 +559,32 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
result->needs_shading = false; result->needs_shading = false;
} else if (def.type == ITEM_NODE) { } else if (def.type == ITEM_NODE) {
switch (f.drawtype) { switch (f.drawtype) {
case NDT_NORMAL:
case NDT_ALLFACES:
case NDT_LIQUID:
case NDT_FLOWINGLIQUID: {
scene::IMesh *cube = g_extrusion_mesh_cache->createCube();
mesh = cloneMesh(cube);
cube->drop();
if (f.drawtype == NDT_FLOWINGLIQUID) {
scaleMesh(mesh, v3f(1.2, 0.03, 1.2));
translateMesh(mesh, v3f(0, -0.57, 0));
} else
scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
// add overlays
postProcessNodeMesh(mesh, f, false, nullptr,
&result->buffer_colors, true);
if (f.drawtype == NDT_ALLFACES)
scaleMesh(mesh, v3f(f.visual_scale));
break;
}
case NDT_PLANTLIKE: { case NDT_PLANTLIKE: {
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
tsrc->getTextureName(f.tiles[0].layers[1].texture_id));
// Add color
const TileLayer &l0 = f.tiles[0].layers[0]; const TileLayer &l0 = f.tiles[0].layers[0];
result->buffer_colors.emplace_back(l0.has_color, l0.color);
const TileLayer &l1 = f.tiles[0].layers[1]; const TileLayer &l1 = f.tiles[0].layers[1];
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(l0.texture_id),
tsrc->getTextureName(l1.texture_id));
// Add color
result->buffer_colors.emplace_back(l0.has_color, l0.color);
result->buffer_colors.emplace_back(l1.has_color, l1.color); result->buffer_colors.emplace_back(l1.has_color, l1.color);
break; break;
} }
case NDT_PLANTLIKE_ROOTED: { case NDT_PLANTLIKE_ROOTED: {
mesh = getExtrudedMesh(tsrc, // Use the plant tile
tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), "");
// Add color
const TileLayer &l0 = f.special_tiles[0].layers[0]; const TileLayer &l0 = f.special_tiles[0].layers[0];
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(l0.texture_id), "");
result->buffer_colors.emplace_back(l0.has_color, l0.color); result->buffer_colors.emplace_back(l0.has_color, l0.color);
break; break;
} }
default: { default: {
// Render non-trivial drawtypes like the actual node // Render all other drawtypes like the actual node
MapNode n(id); MapNode n(id);
if (def.place_param2) if (def.place_param2)
n.setParam2(*def.place_param2); n.setParam2(*def.place_param2);
mesh = createSpecialNodeMesh(client, n, &result->buffer_colors, f); mesh = createGenericNodeMesh(client, n, &result->buffer_colors, f);
scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
break; break;
} }
@ -621,13 +593,13 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) { for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
video::SMaterial &material = buf->getMaterial(); video::SMaterial &material = buf->getMaterial();
// FIXME: overriding this breaks different alpha modes the mesh may have
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialTypeParam = 0.5f; material.MaterialTypeParam = 0.5f;
material.forEachTexture([] (auto &tex) { material.forEachTexture([] (auto &tex) {
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
tex.MagFilter = video::ETMAGF_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST;
}); });
material.BackfaceCulling = cull_backface;
} }
rotateMeshXZby(mesh, -45); rotateMeshXZby(mesh, -45);
@ -648,7 +620,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
const std::string &imagename, const std::string &overlay_name) const std::string &imagename, const std::string &overlay_name)
{ {
// check textures // check textures
video::ITexture *texture = tsrc->getTextureForMesh(imagename); video::ITexture *texture = tsrc->getTexture(imagename);
if (!texture) { if (!texture) {
return NULL; return NULL;
} }
@ -683,56 +655,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialTypeParam = 0.5f; material.MaterialTypeParam = 0.5f;
} }
scaleMesh(mesh, v3f(2.0, 2.0, 2.0)); scaleMesh(mesh, v3f(2));
return mesh; return mesh;
} }
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
bool set_material, const video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors, bool apply_scale)
{
const u32 mc = mesh->getMeshBufferCount();
// Allocate colors for existing buffers
colors->clear();
colors->resize(mc);
for (u32 i = 0; i < mc; ++i) {
const TileSpec *tile = &(f.tiles[i]);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
const TileLayer *layer = &tile->layers[layernum];
if (layer->texture_id == 0)
continue;
if (layernum != 0) {
scene::IMeshBuffer *copy = cloneMeshBuffer(buf);
copy->getMaterial() = buf->getMaterial();
mesh->addMeshBuffer(copy);
copy->drop();
buf = copy;
colors->emplace_back(layer->has_color, layer->color);
} else {
(*colors)[i] = ItemPartColor(layer->has_color, layer->color);
}
video::SMaterial &material = buf->getMaterial();
if (set_material)
layer->applyMaterialOptions(material);
if (mattype) {
material.MaterialType = *mattype;
}
if (layer->animation_frame_count > 1) {
const FrameSpec &animation_frame = (*layer->frames)[0];
material.setTexture(0, animation_frame.texture);
} else {
material.setTexture(0, layer->texture);
}
if (apply_scale && tile->world_aligned) {
u32 n = buf->getVertexCount();
for (u32 k = 0; k != n; ++k)
buf->getTCoords(k) /= layer->scale;
}
}
}
}

View file

@ -92,7 +92,6 @@ public:
WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1); WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1);
virtual ~WieldMeshSceneNode(); virtual ~WieldMeshSceneNode();
void setCube(const ContentFeatures &f, v3f wield_scale);
void setExtruded(const std::string &imagename, const std::string &overlay_image, void setExtruded(const std::string &imagename, const std::string &overlay_image,
v3f wield_scale, ITextureSource *tsrc, u8 num_frames); v3f wield_scale, ITextureSource *tsrc, u8 num_frames);
void setItem(const ItemStack &item, Client *client, void setItem(const ItemStack &item, Client *client,
@ -143,14 +142,3 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename, scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename,
const std::string &overlay_name); const std::string &overlay_name);
/*!
* Applies overlays, textures and optionally materials to the given mesh and
* extracts tile colors for colorization.
* \param mattype overrides the buffer's material type, but can also
* be NULL to leave the original material.
* \param colors returns the colors of the mesh buffers in the mesh.
*/
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
bool set_material, const video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors, bool apply_scale = false);

View file

@ -3,9 +3,8 @@
// Copyright (C) 2018 rubenwardy <rw@rubenwardy.com> // Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
#pragma once #pragma once
#include "config.h"
#include "convert_json.h"
#include "irrlichttypes.h" #include "irrlichttypes.h"
#include <string>
enum class ContentType enum class ContentType
{ {

View file

@ -47,7 +47,7 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
} }
// Add new mods // Add new mods
for (int want_from_modpack = 1; want_from_modpack >= 0; --want_from_modpack) { for (bool want_from_modpack : {true, false}) {
// First iteration: // First iteration:
// Add all the mods that come from modpacks // Add all the mods that come from modpacks
// Second iteration: // Second iteration:
@ -56,9 +56,12 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
std::set<std::string> seen_this_iteration; std::set<std::string> seen_this_iteration;
for (const ModSpec &mod : new_mods) { for (const ModSpec &mod : new_mods) {
if (mod.part_of_modpack != (bool)want_from_modpack) if (mod.part_of_modpack != want_from_modpack)
continue; continue;
// unrelated to this code, but we want to assert it somewhere
assert(fs::IsPathAbsolute(mod.path));
if (existing_mods.count(mod.name) == 0) { if (existing_mods.count(mod.name) == 0) {
// GOOD CASE: completely new mod. // GOOD CASE: completely new mod.
m_unsatisfied_mods.push_back(mod); m_unsatisfied_mods.push_back(mod);

View file

@ -167,6 +167,7 @@ std::map<std::string, ModSpec> getModsInPath(
mod_path.clear(); mod_path.clear();
mod_path.append(path).append(DIR_DELIM).append(modname); mod_path.append(path).append(DIR_DELIM).append(modname);
mod_path = fs::AbsolutePath(mod_path);
mod_virtual_path.clear(); mod_virtual_path.clear();
// Intentionally uses / to keep paths same on different platforms // Intentionally uses / to keep paths same on different platforms
@ -174,7 +175,7 @@ std::map<std::string, ModSpec> getModsInPath(
ModSpec spec(modname, mod_path, part_of_modpack, mod_virtual_path); ModSpec spec(modname, mod_path, part_of_modpack, mod_virtual_path);
parseModContents(spec); parseModContents(spec);
result.insert(std::make_pair(modname, spec)); result[modname] = std::move(spec);
} }
return result; return result;
} }

View file

@ -25,7 +25,7 @@ struct ModSpec
{ {
std::string name; std::string name;
std::string author; std::string author;
std::string path; std::string path; // absolute path on disk
std::string desc; std::string desc;
int release = 0; int release = 0;

View file

@ -22,9 +22,8 @@
namespace namespace
{ {
bool getGameMinetestConfig(const std::string &game_path, Settings &conf) bool getGameConfig(const std::string &game_path, Settings &conf)
{ {
// TODO: rename this
std::string conf_path = game_path + DIR_DELIM + "minetest.conf"; std::string conf_path = game_path + DIR_DELIM + "minetest.conf";
return conf.readConfigFile(conf_path.c_str()); return conf.readConfigFile(conf_path.c_str());
} }
@ -355,7 +354,7 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
game_settings = Settings::createLayer(SL_GAME); game_settings = Settings::createLayer(SL_GAME);
} }
getGameMinetestConfig(gamespec.path, *game_settings); getGameConfig(gamespec.path, *game_settings);
game_settings->removeSecureSettings(); game_settings->removeSecureSettings();
infostream << "Initializing world at " << final_path << std::endl; infostream << "Initializing world at " << final_path << std::endl;

View file

@ -6,8 +6,7 @@
#include <exception> #include <exception>
#include <cassert> #include <cassert>
#include "gettime.h" #include "log.h" // unused. for convenience.
#include "log.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define FUNCTION_NAME __FUNCTION__ #define FUNCTION_NAME __FUNCTION__

View file

@ -82,7 +82,6 @@ void set_default_settings()
// Client // Client
settings->setDefault("address", ""); settings->setDefault("address", "");
settings->setDefault("enable_sound", "true");
#if defined(__unix__) && !defined(__APPLE__) && !defined (__ANDROID__) #if defined(__unix__) && !defined(__APPLE__) && !defined (__ANDROID__)
// On Linux+X11 (not Linux+Wayland or Linux+XWayland), I've encountered a bug // On Linux+X11 (not Linux+Wayland or Linux+XWayland), I've encountered a bug
// where fake mouse events were generated from touch events if in relative // where fake mouse events were generated from touch events if in relative
@ -270,7 +269,6 @@ void set_default_settings()
settings->setDefault("cinematic", "false"); settings->setDefault("cinematic", "false");
settings->setDefault("camera_smoothing", "0.0"); settings->setDefault("camera_smoothing", "0.0");
settings->setDefault("cinematic_camera_smoothing", "0.7"); settings->setDefault("cinematic_camera_smoothing", "0.7");
settings->setDefault("enable_clouds", "true");
settings->setDefault("view_bobbing_amount", "1.0"); settings->setDefault("view_bobbing_amount", "1.0");
settings->setDefault("fall_bobbing_amount", "0.03"); settings->setDefault("fall_bobbing_amount", "0.03");
settings->setDefault("enable_3d_clouds", "true"); settings->setDefault("enable_3d_clouds", "true");
@ -292,14 +290,11 @@ void set_default_settings()
settings->setDefault("hud_scaling", "1.0"); settings->setDefault("hud_scaling", "1.0");
settings->setDefault("gui_scaling", "1.0"); settings->setDefault("gui_scaling", "1.0");
settings->setDefault("gui_scaling_filter", "false"); settings->setDefault("gui_scaling_filter", "false");
settings->setDefault("gui_scaling_filter_txr2img", "true");
settings->setDefault("smooth_scrolling", "true"); settings->setDefault("smooth_scrolling", "true");
settings->setDefault("desynchronize_mapblock_texture_animation", "false");
settings->setDefault("hud_hotbar_max_width", "1.0"); settings->setDefault("hud_hotbar_max_width", "1.0");
settings->setDefault("enable_local_map_saving", "false"); settings->setDefault("enable_local_map_saving", "false");
settings->setDefault("show_entity_selectionbox", "false"); settings->setDefault("show_entity_selectionbox", "false");
settings->setDefault("ambient_occlusion_gamma", "1.8"); settings->setDefault("ambient_occlusion_gamma", "1.8");
settings->setDefault("enable_particles", "true");
settings->setDefault("arm_inertia", "true"); settings->setDefault("arm_inertia", "true");
settings->setDefault("show_nametag_backgrounds", "true"); settings->setDefault("show_nametag_backgrounds", "true");
settings->setDefault("show_block_bounds_radius_near", "4"); settings->setDefault("show_block_bounds_radius_near", "4");
@ -350,7 +345,7 @@ void set_default_settings()
settings->setDefault("shadow_map_color", "false"); settings->setDefault("shadow_map_color", "false");
settings->setDefault("shadow_filters", "1"); settings->setDefault("shadow_filters", "1");
settings->setDefault("shadow_poisson_filter", "true"); settings->setDefault("shadow_poisson_filter", "true");
settings->setDefault("shadow_update_frames", "8"); settings->setDefault("shadow_update_frames", "16");
settings->setDefault("shadow_soft_radius", "5.0"); settings->setDefault("shadow_soft_radius", "5.0");
settings->setDefault("shadow_sky_body_orbit_tilt", "0.0"); settings->setDefault("shadow_sky_body_orbit_tilt", "0.0");
settings->setDefault("enable_sun_tint", "false"); settings->setDefault("enable_sun_tint", "false");
@ -420,7 +415,6 @@ void set_default_settings()
#endif #endif
// Server // Server
settings->setDefault("disable_escape_sequences", "false");
settings->setDefault("strip_color_codes", "false"); settings->setDefault("strip_color_codes", "false");
#ifndef NDEBUG #ifndef NDEBUG
settings->setDefault("random_mod_load_order", "true"); settings->setDefault("random_mod_load_order", "true");
@ -440,7 +434,6 @@ void set_default_settings()
settings->setDefault("protocol_version_min", "1"); settings->setDefault("protocol_version_min", "1");
settings->setDefault("player_transfer_distance", "0"); settings->setDefault("player_transfer_distance", "0");
settings->setDefault("max_simultaneous_block_sends_per_client", "40"); settings->setDefault("max_simultaneous_block_sends_per_client", "40");
settings->setDefault("time_send_interval", "5");
settings->setDefault("motd", ""); settings->setDefault("motd", "");
settings->setDefault("max_users", "15"); settings->setDefault("max_users", "15");

View file

@ -8,7 +8,6 @@
#include <mutex> #include <mutex>
#include "network/networkprotocol.h" #include "network/networkprotocol.h"
#include "irr_v3d.h" #include "irr_v3d.h"
#include "util/container.h"
#include "util/metricsbackend.h" #include "util/metricsbackend.h"
#include "mapgen/mapgen.h" // for MapgenParams #include "mapgen/mapgen.h" // for MapgenParams
#include "map.h" #include "map.h"

View file

@ -16,6 +16,7 @@
#include "gettext.h" #include "gettext.h"
#include "irrlicht_changes/CGUITTFont.h" #include "irrlicht_changes/CGUITTFont.h"
#include "util/string.h" #include "util/string.h"
#include "guiScrollBar.h"
#include <string> #include <string>
inline u32 clamp_u8(s32 value) inline u32 clamp_u8(s32 value)
@ -28,6 +29,11 @@ inline bool isInCtrlKeys(const irr::EKEY_CODE& kc)
return kc == KEY_LCONTROL || kc == KEY_RCONTROL || kc == KEY_CONTROL; return kc == KEY_LCONTROL || kc == KEY_RCONTROL || kc == KEY_CONTROL;
} }
inline u32 getScrollbarSize(IGUIEnvironment* env)
{
return env->getSkin()->getSize(gui::EGDS_SCROLLBAR_SIZE);
}
GUIChatConsole::GUIChatConsole( GUIChatConsole::GUIChatConsole(
gui::IGUIEnvironment* env, gui::IGUIEnvironment* env,
gui::IGUIElement* parent, gui::IGUIElement* parent,
@ -62,15 +68,14 @@ GUIChatConsole::GUIChatConsole(
} }
const u16 chat_font_size = g_settings->getU16("chat_font_size"); const u16 chat_font_size = g_settings->getU16("chat_font_size");
m_font = g_fontengine->getFont(chat_font_size != 0 ? m_font.grab(g_fontengine->getFont(chat_font_size != 0 ?
rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono); rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono));
if (!m_font) { if (!m_font) {
errorstream << "GUIChatConsole: Unable to load mono font" << std::endl; errorstream << "GUIChatConsole: Unable to load mono font" << std::endl;
} else { } else {
core::dimension2d<u32> dim = m_font->getDimension(L"M"); core::dimension2d<u32> dim = m_font->getDimension(L"M");
m_fontsize = v2u32(dim.Width, dim.Height); m_fontsize = v2u32(dim.Width, dim.Height);
m_font->grab();
} }
m_fontsize.X = MYMAX(m_fontsize.X, 1); m_fontsize.X = MYMAX(m_fontsize.X, 1);
m_fontsize.Y = MYMAX(m_fontsize.Y, 1); m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
@ -81,12 +86,11 @@ GUIChatConsole::GUIChatConsole(
// track ctrl keys for mouse event // track ctrl keys for mouse event
m_is_ctrl_down = false; m_is_ctrl_down = false;
m_cache_clickable_chat_weblinks = g_settings->getBool("clickable_chat_weblinks"); m_cache_clickable_chat_weblinks = g_settings->getBool("clickable_chat_weblinks");
}
GUIChatConsole::~GUIChatConsole() m_scrollbar.reset(new GUIScrollBar(env, this, -1, core::rect<s32>(0, 0, 30, m_height), false, true, tsrc));
{ m_scrollbar->setSubElement(true);
if (m_font) m_scrollbar->setLargeStep(1);
m_font->drop(); m_scrollbar->setSmallStep(1);
} }
void GUIChatConsole::openConsole(f32 scale) void GUIChatConsole::openConsole(f32 scale)
@ -121,6 +125,7 @@ void GUIChatConsole::closeConsole()
m_open = false; m_open = false;
Environment->removeFocus(this); Environment->removeFocus(this);
m_menumgr->deletingMenu(this); m_menumgr->deletingMenu(this);
m_scrollbar->setVisible(false);
} }
void GUIChatConsole::closeConsoleAtOnce() void GUIChatConsole::closeConsoleAtOnce()
@ -180,6 +185,10 @@ void GUIChatConsole::draw()
m_screensize = screensize; m_screensize = screensize;
m_desired_height = m_desired_height_fraction * m_screensize.Y; m_desired_height = m_desired_height_fraction * m_screensize.Y;
reformatConsole(); reformatConsole();
} else if (!m_scrollbar->getAbsolutePosition().isPointInside(core::vector2di(screensize.X, m_height))) {
// the height of the chat window is no longer the height of the scrollbar
// happens while opening/closing the window
updateScrollbar(true);
} }
// Animation // Animation
@ -204,6 +213,9 @@ void GUIChatConsole::reformatConsole()
s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
if (cols <= 0 || rows <= 0) if (cols <= 0 || rows <= 0)
cols = rows = 0; cols = rows = 0;
updateScrollbar(true);
recalculateConsolePosition(); recalculateConsolePosition();
m_chat_backend->reformat(cols, rows); m_chat_backend->reformat(cols, rows);
} }
@ -293,10 +305,17 @@ void GUIChatConsole::drawBackground()
void GUIChatConsole::drawText() void GUIChatConsole::drawText()
{ {
if (m_font == NULL) if (!m_font)
return; return;
ChatBuffer& buf = m_chat_backend->getConsoleBuffer(); ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
core::recti rect;
if (m_scrollbar->isVisible())
rect = core::rect<s32> (0, 0, m_screensize.X - getScrollbarSize(Environment), m_height);
else
rect = AbsoluteClippingRect;
for (u32 row = 0; row < buf.getRows(); ++row) for (u32 row = 0; row < buf.getRows(); ++row)
{ {
const ChatFormattedLine& line = buf.getFormattedLine(row); const ChatFormattedLine& line = buf.getFormattedLine(row);
@ -315,13 +334,13 @@ void GUIChatConsole::drawText()
if (m_font->getType() == irr::gui::EGFT_CUSTOM) { if (m_font->getType() == irr::gui::EGFT_CUSTOM) {
// Draw colored text if possible // Draw colored text if possible
gui::CGUITTFont *tmp = static_cast<gui::CGUITTFont*>(m_font); auto *tmp = static_cast<gui::CGUITTFont*>(m_font.get());
tmp->draw( tmp->draw(
fragment.text, fragment.text,
destrect, destrect,
false, false,
false, false,
&AbsoluteClippingRect); &rect);
} else { } else {
// Otherwise use standard text // Otherwise use standard text
m_font->draw( m_font->draw(
@ -330,10 +349,12 @@ void GUIChatConsole::drawText()
video::SColor(255, 255, 255, 255), video::SColor(255, 255, 255, 255),
false, false,
false, false,
&AbsoluteClippingRect); &rect);
} }
} }
} }
updateScrollbar();
} }
void GUIChatConsole::drawPrompt() void GUIChatConsole::drawPrompt()
@ -680,6 +701,11 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
prompt.input(std::wstring(event.StringInput.Str->c_str())); prompt.input(std::wstring(event.StringInput.Str->c_str()));
return true; return true;
} }
else if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED &&
(void*) event.GUIEvent.Caller == (void*) m_scrollbar.get())
{
m_chat_backend->getConsoleBuffer().scrollAbsolute(m_scrollbar->getPos());
}
return Parent ? Parent->OnEvent(event) : false; return Parent ? Parent->OnEvent(event) : false;
} }
@ -692,6 +718,7 @@ void GUIChatConsole::setVisible(bool visible)
m_height = 0; m_height = 0;
recalculateConsolePosition(); recalculateConsolePosition();
} }
m_scrollbar->setVisible(visible);
} }
bool GUIChatConsole::weblinkClick(s32 col, s32 row) bool GUIChatConsole::weblinkClick(s32 col, s32 row)
@ -763,3 +790,18 @@ void GUIChatConsole::updatePrimarySelection()
std::string selected = wide_to_utf8(wselected); std::string selected = wide_to_utf8(wselected);
Environment->getOSOperator()->copyToPrimarySelection(selected.c_str()); Environment->getOSOperator()->copyToPrimarySelection(selected.c_str());
} }
void GUIChatConsole::updateScrollbar(bool update_size)
{
ChatBuffer &buf = m_chat_backend->getConsoleBuffer();
m_scrollbar->setMin(buf.getTopScrollPos());
m_scrollbar->setMax(buf.getBottomScrollPos());
m_scrollbar->setPos(buf.getScrollPosition());
m_scrollbar->setPageSize(m_fontsize.Y * buf.getLineCount());
m_scrollbar->setVisible(m_scrollbar->getMin() != m_scrollbar->getMax());
if (update_size) {
const core::rect<s32> rect (m_screensize.X - getScrollbarSize(Environment), 0, m_screensize.X, m_height);
m_scrollbar->setRelativePosition(rect);
}
}

View file

@ -8,8 +8,10 @@
#include "modalMenu.h" #include "modalMenu.h"
#include "chat.h" #include "chat.h"
#include "config.h" #include "config.h"
#include "irr_ptr.h"
class Client; class Client;
class GUIScrollBar;
class GUIChatConsole : public gui::IGUIElement class GUIChatConsole : public gui::IGUIElement
{ {
@ -20,7 +22,6 @@ public:
ChatBackend* backend, ChatBackend* backend,
Client* client, Client* client,
IMenuManager* menumgr); IMenuManager* menumgr);
virtual ~GUIChatConsole();
// Open the console (height = desired fraction of screen size) // Open the console (height = desired fraction of screen size)
// This doesn't open immediately but initiates an animation. // This doesn't open immediately but initiates an animation.
@ -76,10 +77,13 @@ private:
// If the selected text changed, we need to update the (X11) primary selection. // If the selected text changed, we need to update the (X11) primary selection.
void updatePrimarySelection(); void updatePrimarySelection();
void updateScrollbar(bool update_size = false);
private: private:
ChatBackend* m_chat_backend; ChatBackend* m_chat_backend;
Client* m_client; Client* m_client;
IMenuManager* m_menumgr; IMenuManager* m_menumgr;
irr_ptr<GUIScrollBar> m_scrollbar;
// current screen size // current screen size
v2u32 m_screensize; v2u32 m_screensize;
@ -116,7 +120,7 @@ private:
video::SColor m_background_color = video::SColor(255, 0, 0, 0); video::SColor m_background_color = video::SColor(255, 0, 0, 0);
// font // font
gui::IGUIFont *m_font = nullptr; irr_ptr<gui::IGUIFont> m_font;
v2u32 m_fontsize; v2u32 m_fontsize;
// Enable clickable chat weblinks // Enable clickable chat weblinks

View file

@ -130,7 +130,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
// create soundmanager // create soundmanager
#if USE_SOUND #if USE_SOUND
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) { if (g_sound_manager_singleton.get()) {
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
std::make_unique<MenuMusicFetcher>()); std::make_unique<MenuMusicFetcher>());
} }

View file

@ -11,6 +11,12 @@
#include <cassert> #include <cassert>
#include <list> #include <list>
#include "IGUIEnvironment.h"
namespace irr::gui {
class IGUIStaticText;
}
class IGameCallback class IGameCallback
{ {
public: public:

View file

@ -4,8 +4,10 @@
#pragma once #pragma once
#include "irrlichttypes_extrabloated.h" #include "IGUIElement.h"
#include "irrlichttypes_bloated.h"
#include "irr_ptr.h" #include "irr_ptr.h"
#include "util/string.h" #include "util/string.h"
#ifdef __ANDROID__ #ifdef __ANDROID__
#include <porting_android.h> #include <porting_android.h>

View file

@ -13,6 +13,7 @@
class ISimpleTextureSource; class ISimpleTextureSource;
namespace irr::gui namespace irr::gui
{ {
class IGUIButton;
class IGUIImage; class IGUIImage;
} }

View file

@ -1,14 +0,0 @@
// Luanti
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (C) 2021 x2048, Dmitry Kostenko <codeforsmile@gmail.com>
#include "lighting.h"
AutoExposure::AutoExposure()
: luminance_min(-3.f),
luminance_max(-3.f),
exposure_correction(0.0f),
speed_dark_bright(1000.f),
speed_bright_dark(1000.f),
center_weight_power(1.f)
{}

View file

@ -29,7 +29,14 @@ struct AutoExposure
/// @brief Power value for center-weighted metering. Value of 1.0 measures entire screen uniformly /// @brief Power value for center-weighted metering. Value of 1.0 measures entire screen uniformly
float center_weight_power; float center_weight_power;
AutoExposure(); constexpr AutoExposure()
: luminance_min(-3.f),
luminance_max(-3.f),
exposure_correction(0.0f),
speed_dark_bright(1000.f),
speed_bright_dark(1000.f),
center_weight_power(1.f)
{}
}; };
/** /**

View file

@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map):
assert(map); assert(map);
} }
void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent)
bool load_if_inexistent)
{ {
TimeTaker timer1("initialEmerge", &emerge_time); TimeTaker timer1("initialEmerge", &emerge_time);
assert(m_map); assert(m_map);
// Units of these are MapBlocks
v3s16 p_min = blockpos_min;
v3s16 p_max = blockpos_max;
VoxelArea block_area_nodes VoxelArea block_area_nodes
(p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
@ -775,6 +770,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
infostream<<std::endl; infostream<<std::endl;
} }
const bool all_new = m_area.hasEmptyExtent() || block_area_nodes.contains(m_area);
addArea(block_area_nodes); addArea(block_area_nodes);
for(s32 z=p_min.Z; z<=p_max.Z; z++) for(s32 z=p_min.Z; z<=p_max.Z; z++)
@ -812,16 +808,12 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
setFlags(a, VOXELFLAG_NO_DATA); setFlags(a, VOXELFLAG_NO_DATA);
} }
} }
/*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
{
// Mark that block was loaded as blank
flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
}*/
m_loaded_blocks[p] = flags; m_loaded_blocks[p] = flags;
} }
m_is_dirty = false; if (all_new)
m_is_dirty = false;
} }
void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks, void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
@ -834,6 +826,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
/* /*
Copy data of all blocks Copy data of all blocks
*/ */
assert(!m_loaded_blocks.empty());
for (auto &loaded_block : m_loaded_blocks) { for (auto &loaded_block : m_loaded_blocks) {
v3s16 p = loaded_block.first; v3s16 p = loaded_block.first;
MapBlock *block = m_map->getBlockNoCreateNoEx(p); MapBlock *block = m_map->getBlockNoCreateNoEx(p);

View file

@ -298,9 +298,6 @@ protected:
u32 needed_count); u32 needed_count);
}; };
#define VMANIP_BLOCK_DATA_INEXIST 1
#define VMANIP_BLOCK_CONTAINS_CIGNORE 2
class MMVManip : public VoxelManipulator class MMVManip : public VoxelManipulator
{ {
public: public:
@ -344,4 +341,8 @@ protected:
value = flags describing the block value = flags describing the block
*/ */
std::map<v3s16, u8> m_loaded_blocks; std::map<v3s16, u8> m_loaded_blocks;
enum : u8 {
VMANIP_BLOCK_DATA_INEXIST = 1 << 0,
};
}; };

View file

@ -73,6 +73,12 @@ MapBlock::~MapBlock()
porting::TrackFreedMemory(sizeof(MapNode) * nodecount); porting::TrackFreedMemory(sizeof(MapNode) * nodecount);
} }
static inline size_t get_max_objects_per_block()
{
u16 ret = g_settings->getU16("max_objects_per_block");
return MYMAX(256, ret);
}
bool MapBlock::onObjectsActivation() bool MapBlock::onObjectsActivation()
{ {
// Ignore if no stored objects (to not set changed flag) // Ignore if no stored objects (to not set changed flag)
@ -84,7 +90,7 @@ bool MapBlock::onObjectsActivation()
<< "activating " << count << " objects in block " << getPos() << "activating " << count << " objects in block " << getPos()
<< std::endl; << std::endl;
if (count > g_settings->getU16("max_objects_per_block")) { if (count > get_max_objects_per_block()) {
errorstream << "suspiciously large amount of objects detected: " errorstream << "suspiciously large amount of objects detected: "
<< count << " in " << getPos() << "; removing all of them." << count << " in " << getPos() << "; removing all of them."
<< std::endl; << std::endl;
@ -99,7 +105,7 @@ bool MapBlock::onObjectsActivation()
bool MapBlock::saveStaticObject(u16 id, const StaticObject &obj, u32 reason) bool MapBlock::saveStaticObject(u16 id, const StaticObject &obj, u32 reason)
{ {
if (m_static_objects.getStoredSize() >= g_settings->getU16("max_objects_per_block")) { if (m_static_objects.getStoredSize() >= get_max_objects_per_block()) {
warningstream << "MapBlock::saveStaticObject(): Trying to store id = " << id warningstream << "MapBlock::saveStaticObject(): Trying to store id = " << id
<< " statically but block " << getPos() << " already contains " << " statically but block " << getPos() << " already contains "
<< m_static_objects.getStoredSize() << " objects." << m_static_objects.getStoredSize() << " objects."

Some files were not shown because too many files have changed in this diff Show more