Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2
26
.github/workflows/png_file_checks.yml
vendored
Normal 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
|
|
@ -14,6 +14,9 @@ https://www.apache.org/licenses/LICENSE-2.0.html
|
|||
Textures by Zughy are under CC 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
|
||||
https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
|
@ -64,7 +67,13 @@ Zughy:
|
|||
textures/base/pack/settings_info.png
|
||||
textures/base/pack/settings_reset.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_unavailable.png
|
||||
|
||||
cx384:
|
||||
textures/base/pack/server_view_mods.png
|
||||
textures/base/pack/server_view_mods_unavailable.png
|
||||
|
||||
appgurueu:
|
||||
textures/base/pack/server_incompatible.png
|
||||
|
|
|
@ -308,23 +308,26 @@ core.register_entity(":__builtin:falling_node", {
|
|||
|
||||
core.remove_node(bcp)
|
||||
else
|
||||
-- We are placing on top so check what's there
|
||||
np.y = np.y + 1
|
||||
end
|
||||
|
||||
-- Check what's here
|
||||
local n2 = core.get_node(np)
|
||||
local nd = core.registered_nodes[n2.name]
|
||||
-- If it's not air or liquid, remove node and replace it with
|
||||
-- it's drops
|
||||
if n2.name ~= "air" and (not nd or nd.liquidtype ~= "source") then
|
||||
if nd and nd.buildable_to == false then
|
||||
local n2 = core.get_node(np)
|
||||
local nd = core.registered_nodes[n2.name]
|
||||
if not nd or nd.buildable_to then
|
||||
core.remove_node(np)
|
||||
else
|
||||
-- 'walkable' is used to mean "falling nodes can't replace this"
|
||||
-- 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)
|
||||
-- If it's still there, it might be protected
|
||||
if core.get_node(np).name == n2.name then
|
||||
return false
|
||||
end
|
||||
else
|
||||
core.remove_node(np)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
105
builtin/mainmenu/dlg_server_list_mods.lua
Normal 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
|
|
@ -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_reinstall_mtg.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua")
|
||||
dofile(menupath .. DIR_DELIM .. "dlg_server_list_mods.lua")
|
||||
|
||||
local tabs = {
|
||||
content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"),
|
||||
|
|
|
@ -161,6 +161,26 @@ local function get_formspec(tabview, name, tabdata)
|
|||
core.formspec_escape(gamedata.serverdescription) .. "]"
|
||||
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 can_view_clients_list = clients_list and #clients_list > 0
|
||||
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 .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir ..
|
||||
"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
|
||||
|
||||
-- URL button
|
||||
if selected_server.url then
|
||||
retval = retval .. "tooltip[btn_server_url;" .. fgettext("Open server website") .. "]"
|
||||
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;]"
|
||||
else
|
||||
retval = retval .. "image[3.6,1.4;0.3,0.3;" .. core.formspec_escape(defaulttexturedir ..
|
||||
"server_url_unavailable.png") .. "]"
|
||||
end
|
||||
|
||||
-- Favorites toggle button
|
||||
if is_selected_fav() then
|
||||
retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]"
|
||||
retval = retval .. "style[btn_delete_favorite;padding=6]"
|
||||
|
@ -468,6 +496,14 @@ local function main_button_handler(tabview, fields, name, tabdata)
|
|||
return true
|
||||
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
|
||||
tabdata.search_for = ""
|
||||
menudata.search_result = nil
|
||||
|
|
|
@ -377,17 +377,12 @@ fog_start (Fog start) float 0.4 0.0 0.99
|
|||
|
||||
[**Clouds]
|
||||
|
||||
# Clouds are a client-side effect.
|
||||
enable_clouds (Clouds) bool true
|
||||
|
||||
# Use 3D cloud look instead of flat.
|
||||
#
|
||||
# Requires: enable_clouds
|
||||
# Allow clouds to look 3D instead of flat.
|
||||
enable_3d_clouds (3D clouds) bool true
|
||||
|
||||
# Use smooth cloud shading.
|
||||
#
|
||||
# Requires: enable_3d_clouds, enable_clouds
|
||||
# Requires: enable_3d_clouds
|
||||
soft_clouds (Soft clouds) bool false
|
||||
|
||||
[**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.
|
||||
performance_tradeoffs (Tradeoffs for performance) bool false
|
||||
|
||||
# Adds particles when digging a node.
|
||||
enable_particles (Digging particles) bool true
|
||||
|
||||
|
||||
[**Waving Nodes]
|
||||
|
||||
|
@ -667,8 +659,7 @@ sound_volume (Volume) float 0.8 0.0 1.0
|
|||
# Volume multiplier when the window is unfocused.
|
||||
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
|
||||
# sound system is disabled (enable_sound=false).
|
||||
# Whether to mute sounds. You can unmute sounds at any time.
|
||||
# In-game, you can toggle the mute state with the mute key or by using the
|
||||
# pause menu.
|
||||
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).
|
||||
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.
|
||||
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.
|
||||
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
|
||||
cloud_radius (Cloud radius) int 12 1 62
|
||||
|
||||
# Whether node texture animations should be desynchronized per mapblock.
|
||||
desynchronize_mapblock_texture_animation (Desynchronize block animation) bool false
|
||||
cloud_radius (Cloud radius) int 12 8 62
|
||||
|
||||
# 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.
|
||||
|
@ -1942,7 +1924,7 @@ shadow_poisson_filter (Poisson filtering) bool true
|
|||
# Minimum value: 1; maximum value: 16
|
||||
#
|
||||
# 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.
|
||||
# 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.
|
||||
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.
|
||||
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
|
||||
|
||||
# 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.
|
||||
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.
|
||||
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.
|
||||
keymap_forward (Forward key) key KEY_KEY_W
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ centroid varying float nightRatio;
|
|||
varying highp vec3 eyeVec;
|
||||
varying float nightFactor;
|
||||
|
||||
#ifdef ENABLE_DYNAMIC_SHADOWS
|
||||
#if (MATERIAL_WAVING_LIQUID && defined(ENABLE_WATER_REFLECTIONS))
|
||||
vec4 perm(vec4 x)
|
||||
{
|
||||
|
@ -536,7 +535,7 @@ void main(void)
|
|||
col.rgb += water_reflect_color * f_shadow_factor * brightness_factor;
|
||||
#endif
|
||||
|
||||
#if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WAVING_LIQUID)
|
||||
#if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WATER_REFLECTIONS)
|
||||
// Apply specular to blocks.
|
||||
if (dot(v_LightDirection, vNormal) < 0.0) {
|
||||
// This intensity is a placeholder and should be replaced by proper specular maps.
|
||||
|
|
|
@ -5044,7 +5044,7 @@ inside the VoxelManip.
|
|||
can use `core.emerge_area` to make sure that the area you want to
|
||||
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
|
||||
VoxelManips (see above section), the internal buffers are not updated. For
|
||||
this reason, it is strongly encouraged to complete the usage of a particular
|
||||
|
@ -5059,9 +5059,11 @@ inside the VoxelManip.
|
|||
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`.
|
||||
* 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
|
||||
the map.
|
||||
* **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
|
||||
to `true` if left out.
|
||||
* `update_liquids()`: Update liquid flow
|
||||
* `was_modified()`: Returns `true` if the data in the voxel manipulator has been modified
|
||||
since it was last read from the map. This means you have to call `get_data` again.
|
||||
* `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.
|
||||
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.
|
||||
* Note: this doesn't do what you think it does and is subject to removal. Don't use it!
|
||||
|
|
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 183 B After Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 153 B After Width: | Height: | Size: 121 B |
Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 115 B |
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 124 B |
|
@ -12,6 +12,7 @@ unittests.list = {}
|
|||
-- player = false, -- Does test require a player?
|
||||
-- map = false, -- Does test require map access?
|
||||
-- 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)
|
||||
local def = table.copy(opts or {})
|
||||
|
@ -47,8 +48,18 @@ local function await(invoke)
|
|||
return coroutine.yield()
|
||||
end
|
||||
|
||||
local function printf(fmt, ...)
|
||||
print(fmt:format(...))
|
||||
end
|
||||
|
||||
function unittests.run_one(idx, counters, out_callback, player, pos)
|
||||
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
|
||||
player = nil
|
||||
elseif player == nil then
|
||||
|
@ -70,8 +81,10 @@ function unittests.run_one(idx, counters, out_callback, player, pos)
|
|||
if not status then
|
||||
core.log("error", err)
|
||||
end
|
||||
print(string.format("[%s] %s - %dms",
|
||||
status and "PASS" or "FAIL", def.name, ms_taken))
|
||||
printf("[%s] %s - %dms", 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.total = counters.total + 1
|
||||
if status then
|
||||
|
@ -160,11 +173,11 @@ function unittests.run_all()
|
|||
-- Print stats
|
||||
assert(#unittests.list == counters.total)
|
||||
print(string.rep("+", 80))
|
||||
print(string.format("Devtest Unit Test Results: %s",
|
||||
counters.total == counters.passed and "PASSED" or "FAILED"))
|
||||
print(string.format(" %d / %d failed tests.",
|
||||
counters.total - counters.passed, counters.total))
|
||||
print(string.format(" Testing took %dms total.", counters.time))
|
||||
local passed = counters.total == counters.passed
|
||||
printf("Devtest Unit Test Results: %s", passed and "PASSED" or "FAILED")
|
||||
printf(" %d / %d failed tests.",
|
||||
counters.total - counters.passed, counters.total)
|
||||
printf(" Testing took %dms total.", counters.time)
|
||||
print(string.rep("+", 80))
|
||||
unittests.on_finished(counters.total == counters.passed)
|
||||
return counters.total == counters.passed
|
||||
|
|
|
@ -34,3 +34,70 @@ local function test_raycast_pointabilities(player, pos1)
|
|||
end
|
||||
|
||||
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})
|
||||
|
|
|
@ -34,7 +34,7 @@ enum E_DEBUG_SCENE_TYPE
|
|||
EDS_BBOX_ALL = EDS_BBOX | EDS_BBOX_BUFFERS,
|
||||
|
||||
//! Show all debug infos
|
||||
EDS_FULL = 0xffffffff
|
||||
EDS_FULL = 0xffff
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "IGUIElement.h"
|
||||
#include "SColor.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "IEventReceiver.h"
|
||||
#include "EGUIElementTypes.h"
|
||||
#include "EGUIAlignment.h"
|
||||
#include "IGUIEnvironment.h"
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
@ -19,6 +18,8 @@ namespace irr
|
|||
{
|
||||
namespace gui
|
||||
{
|
||||
class IGUIEnvironment;
|
||||
|
||||
//! Base class of all GUI elements.
|
||||
class IGUIElement : virtual public IReferenceCounted, public IEventReceiver
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "IGUIElement.h"
|
||||
#include "SColor.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
|
|
@ -387,6 +387,14 @@ public:
|
|||
pass currently is active they can render the correct part of their geometry. */
|
||||
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.
|
||||
/** This can be used to easily draw and/or store two
|
||||
independent scenes at the same time. The mesh cache will be
|
||||
|
|
|
@ -403,14 +403,14 @@ public:
|
|||
their geometry because it is their only reason for existence,
|
||||
for example the OctreeSceneNode.
|
||||
\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;
|
||||
}
|
||||
|
||||
//! Gets the automatic culling state.
|
||||
/** \return The automatic culling state. */
|
||||
u32 getAutomaticCulling() const
|
||||
u16 getAutomaticCulling() const
|
||||
{
|
||||
return AutomaticCullingState;
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ public:
|
|||
/** 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.
|
||||
\param state The debug data visibility state to be used. */
|
||||
virtual void setDebugDataVisible(u32 state)
|
||||
virtual void setDebugDataVisible(u16 state)
|
||||
{
|
||||
DebugDataVisible = state;
|
||||
}
|
||||
|
@ -427,7 +427,7 @@ public:
|
|||
//! Returns if debug data like bounding boxes are drawn.
|
||||
/** \return A bitwise OR of the debug data values from
|
||||
@ref irr::scene::E_DEBUG_SCENE_TYPE that are currently visible. */
|
||||
u32 isDebugDataVisible() const
|
||||
u16 isDebugDataVisible() const
|
||||
{
|
||||
return DebugDataVisible;
|
||||
}
|
||||
|
@ -581,10 +581,10 @@ protected:
|
|||
s32 ID;
|
||||
|
||||
//! Automatic culling state
|
||||
u32 AutomaticCullingState;
|
||||
u16 AutomaticCullingState;
|
||||
|
||||
//! Flag if debug data should be drawn, such as Bounding Boxes.
|
||||
u32 DebugDataVisible;
|
||||
u16 DebugDataVisible;
|
||||
|
||||
//! Is the node visible?
|
||||
bool IsVisible;
|
||||
|
|
|
@ -20,7 +20,7 @@ class ITexture;
|
|||
|
||||
//! Flag for MaterialTypeParam (in combination with EMT_ONETEXTURE_BLEND) or for BlendFactor
|
||||
//! BlendFunc = source * sourceFactor + dest * destFactor
|
||||
enum E_BLEND_FACTOR
|
||||
enum E_BLEND_FACTOR : u8
|
||||
{
|
||||
EBF_ZERO = 0, //!< src & dest (0, 0, 0, 0)
|
||||
EBF_ONE, //!< src & dest (1, 1, 1, 1)
|
||||
|
@ -36,7 +36,7 @@ enum E_BLEND_FACTOR
|
|||
};
|
||||
|
||||
//! Values defining the blend operation
|
||||
enum E_BLEND_OPERATION
|
||||
enum E_BLEND_OPERATION : u8
|
||||
{
|
||||
EBO_NONE = 0, //!< No blending happens
|
||||
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
|
||||
enum E_MODULATE_FUNC
|
||||
enum E_MODULATE_FUNC : u8
|
||||
{
|
||||
EMFN_MODULATE_1X = 1,
|
||||
EMFN_MODULATE_2X = 2,
|
||||
|
@ -59,7 +59,7 @@ enum E_MODULATE_FUNC
|
|||
};
|
||||
|
||||
//! 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)
|
||||
ECFN_DISABLED = 0,
|
||||
|
@ -82,7 +82,7 @@ enum E_COMPARISON_FUNC
|
|||
};
|
||||
|
||||
//! Enum values for enabling/disabling color planes for rendering
|
||||
enum E_COLOR_PLANE
|
||||
enum E_COLOR_PLANE : u8
|
||||
{
|
||||
//! No color enabled
|
||||
ECP_NONE = 0,
|
||||
|
@ -103,7 +103,7 @@ enum E_COLOR_PLANE
|
|||
//! Source of the alpha value to take
|
||||
/** This is currently only supported in EMT_ONETEXTURE_BLEND. You can use an
|
||||
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
|
||||
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
|
||||
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
|
||||
EAAM_OFF = 0,
|
||||
|
@ -202,7 +202,7 @@ const c8 *const PolygonOffsetDirectionNames[] = {
|
|||
};
|
||||
|
||||
//! For SMaterial.ZWriteEnable
|
||||
enum E_ZWRITE
|
||||
enum E_ZWRITE : u8
|
||||
{
|
||||
//! zwrite always disabled for this material
|
||||
EZW_OFF = 0,
|
||||
|
@ -240,10 +240,10 @@ public:
|
|||
//! Default constructor. Creates a solid material
|
||||
SMaterial() :
|
||||
MaterialType(EMT_SOLID), ColorParam(0, 0, 0, 0),
|
||||
MaterialTypeParam(0.0f), Thickness(1.0f), ZBuffer(ECFN_LESSEQUAL),
|
||||
AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL),
|
||||
BlendOperation(EBO_NONE), BlendFactor(0.0f), PolygonOffsetDepthBias(0.f),
|
||||
PolygonOffsetSlopeScale(0.f), Wireframe(false), PointCloud(false),
|
||||
MaterialTypeParam(0.0f), Thickness(1.0f), BlendFactor(0.0f),
|
||||
PolygonOffsetDepthBias(0.f), PolygonOffsetSlopeScale(0.f),
|
||||
ZBuffer(ECFN_LESSEQUAL), AntiAliasing(EAAM_SIMPLE), ColorMask(ECP_ALL),
|
||||
BlendOperation(EBO_NONE), Wireframe(false), PointCloud(false),
|
||||
ZWriteEnable(EZW_AUTO),
|
||||
BackfaceCulling(true), FrontfaceCulling(false), FogEnable(false),
|
||||
UseMipMaps(true)
|
||||
|
@ -268,28 +268,6 @@ public:
|
|||
//! Thickness of non-3dimensional elements such as lines and points.
|
||||
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
|
||||
/** textureBlendFunc/textureBlendFuncSeparate functions should be used to write
|
||||
properly blending factors to this parameter.
|
||||
|
@ -304,11 +282,7 @@ public:
|
|||
|
||||
//! A constant z-buffer offset for a polygon/line/point
|
||||
/** 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 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). */
|
||||
On OpenGL you get units which are multiplied by the smallest value that is guaranteed to produce a resolvable offset. */
|
||||
f32 PolygonOffsetDepthBias;
|
||||
|
||||
//! 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. */
|
||||
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
|
||||
bool Wireframe : 1;
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ static const char *const aTextureClampNames[] = {
|
|||
//! Texture minification filter.
|
||||
/** Used when scaling textures down. See the documentation on OpenGL's
|
||||
`GL_TEXTURE_MIN_FILTER` for more information. */
|
||||
enum E_TEXTURE_MIN_FILTER
|
||||
enum E_TEXTURE_MIN_FILTER : u8
|
||||
{
|
||||
//! Aka nearest-neighbor.
|
||||
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
|
||||
`GL_TEXTURE_MAG_FILTER` for more information.
|
||||
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.
|
||||
ETMAGF_NEAREST = 0,
|
||||
|
|
|
@ -253,7 +253,7 @@ void CAnimatedMeshSceneNode::render()
|
|||
// for debug purposes only:
|
||||
if (DebugDataVisible && PassCount == 1) {
|
||||
video::SMaterial debug_mat;
|
||||
debug_mat.AntiAliasing = 0;
|
||||
debug_mat.AntiAliasing = video::EAAM_OFF;
|
||||
driver->setMaterial(debug_mat);
|
||||
// show normals
|
||||
if (DebugDataVisible & scene::EDS_NORMALS) {
|
||||
|
@ -276,9 +276,6 @@ void CAnimatedMeshSceneNode::render()
|
|||
debug_mat.ZBuffer = video::ECFN_DISABLED;
|
||||
driver->setMaterial(debug_mat);
|
||||
|
||||
if (DebugDataVisible & scene::EDS_BBOX)
|
||||
driver->draw3DBox(Box, video::SColor(255, 255, 255, 255));
|
||||
|
||||
// show bounding box
|
||||
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) {
|
||||
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
|
||||
if (DebugDataVisible & scene::EDS_SKELETON) {
|
||||
if (Mesh->getMeshType() == EAMT_SKINNED) {
|
||||
|
|
|
@ -91,7 +91,7 @@ public:
|
|||
|
||||
private:
|
||||
//! Currently used FileSystemType
|
||||
EFileSystemType FileSystemType;
|
||||
EFileSystemType FileSystemType = FILESYSTEM_NATIVE;
|
||||
//! WorkingDirectory for Native and Virtual filesystems
|
||||
io::path WorkingDirectory[2];
|
||||
//! currently attached ArchiveLoaders
|
||||
|
|
|
@ -948,7 +948,7 @@ IGUIElement *CGUIEnvironment::getNextElement(bool reverse, bool group)
|
|||
// this element is not part of the tab cycle,
|
||||
// but its parent might be...
|
||||
IGUIElement *el = Focus;
|
||||
while (el && el->getParent() && startOrder == -1) {
|
||||
while (el->getParent() && startOrder == -1) {
|
||||
el = el->getParent();
|
||||
startOrder = el->getTabOrder();
|
||||
}
|
||||
|
|
|
@ -109,12 +109,10 @@ void CMeshSceneNode::render()
|
|||
// for debug purposes only:
|
||||
if (DebugDataVisible && PassCount == 1) {
|
||||
video::SMaterial m;
|
||||
m.AntiAliasing = 0;
|
||||
m.AntiAliasing = video::EAAM_OFF;
|
||||
m.ZBuffer = video::ECFN_DISABLED;
|
||||
driver->setMaterial(m);
|
||||
|
||||
if (DebugDataVisible & scene::EDS_BBOX) {
|
||||
driver->draw3DBox(Box, video::SColor(255, 255, 255, 255));
|
||||
}
|
||||
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) {
|
||||
for (u32 g = 0; g < Mesh->getMeshBufferCount(); ++g) {
|
||||
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) {
|
||||
// draw normals
|
||||
const f32 debugNormalLength = 1.f;
|
||||
|
|
|
@ -619,20 +619,17 @@ void CNullDriver::draw3DBox(const core::aabbox3d<f32> &box, SColor color)
|
|||
core::vector3df edges[8];
|
||||
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);
|
||||
draw3DLine(edges[1], edges[3], color);
|
||||
draw3DLine(edges[3], edges[7], color);
|
||||
draw3DLine(edges[7], edges[5], color);
|
||||
draw3DLine(edges[0], edges[2], color);
|
||||
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);
|
||||
const static u16 box_indices[24] = {
|
||||
5, 1, 1, 3, 3, 7, 7, 5, 0, 2, 2, 6, 6, 4, 4, 0, 1, 0, 3, 2, 7, 6, 5, 4
|
||||
};
|
||||
|
||||
drawVertexPrimitiveList(v, 8, box_indices, 12, EVT_STANDARD, scene::EPT_LINES);
|
||||
}
|
||||
|
||||
//! draws an 2d image
|
||||
|
@ -1314,7 +1311,7 @@ void CNullDriver::runOcclusionQuery(scene::ISceneNode *node, bool visible)
|
|||
OcclusionQueries[index].Run = 0;
|
||||
if (!visible) {
|
||||
SMaterial mat;
|
||||
mat.AntiAliasing = 0;
|
||||
mat.AntiAliasing = video::EAAM_OFF;
|
||||
mat.ColorMask = ECP_NONE;
|
||||
mat.ZWriteEnable = EZW_OFF;
|
||||
setMaterial(mat);
|
||||
|
|
|
@ -137,6 +137,9 @@ public:
|
|||
Images.clear();
|
||||
}
|
||||
|
||||
if (!name.empty())
|
||||
Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str());
|
||||
|
||||
Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);
|
||||
|
||||
TEST_GL_ERROR(Driver);
|
||||
|
@ -247,6 +250,9 @@ public:
|
|||
break;
|
||||
}
|
||||
|
||||
if (!name.empty())
|
||||
Driver->irrGlObjectLabel(GL_TEXTURE, TextureName, name.c_str());
|
||||
|
||||
Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);
|
||||
if (TEST_GL_ERROR(Driver)) {
|
||||
char msg[256];
|
||||
|
|
|
@ -2462,66 +2462,6 @@ void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start,
|
|||
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.
|
||||
void COpenGLDriver::draw3DLine(const core::vector3df &start,
|
||||
const core::vector3df &end, SColor color)
|
||||
|
|
|
@ -170,9 +170,6 @@ public:
|
|||
const core::position2d<s32> &end,
|
||||
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.
|
||||
virtual void draw3DLine(const core::vector3df &start,
|
||||
const core::vector3df &end,
|
||||
|
|
|
@ -1065,6 +1065,10 @@ public:
|
|||
void irrGlCompressedTexSubImage2D(GLenum target, GLint level,
|
||||
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
|
||||
GLenum format, GLsizei imageSize, const void *data);
|
||||
inline void irrGlObjectLabel(GLenum identifier, GLuint name, const char *label)
|
||||
{
|
||||
// unimplemented
|
||||
}
|
||||
|
||||
// shader programming
|
||||
void extGlGenPrograms(GLsizei n, GLuint *programs);
|
||||
|
|
|
@ -490,13 +490,19 @@ void CSceneManager::drawAll()
|
|||
// let all nodes register themselves
|
||||
OnRegisterSceneNode();
|
||||
|
||||
const auto &render_node = [this] (ISceneNode *node) {
|
||||
u32 flags = node->isDebugDataVisible();
|
||||
node->setDebugDataVisible((flags & DebugDataMask) | DebugDataBits);
|
||||
node->render();
|
||||
};
|
||||
|
||||
// render camera scenes
|
||||
{
|
||||
CurrentRenderPass = ESNRP_CAMERA;
|
||||
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
|
||||
|
||||
for (auto *node : CameraList)
|
||||
node->render();
|
||||
render_node(node);
|
||||
|
||||
CameraList.clear();
|
||||
}
|
||||
|
@ -507,7 +513,7 @@ void CSceneManager::drawAll()
|
|||
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
|
||||
|
||||
for (auto *node : SkyBoxList)
|
||||
node->render();
|
||||
render_node(node);
|
||||
|
||||
SkyBoxList.clear();
|
||||
}
|
||||
|
@ -520,7 +526,7 @@ void CSceneManager::drawAll()
|
|||
std::sort(SolidNodeList.begin(), SolidNodeList.end());
|
||||
|
||||
for (auto &it : SolidNodeList)
|
||||
it.Node->render();
|
||||
render_node(it.Node);
|
||||
|
||||
SolidNodeList.clear();
|
||||
}
|
||||
|
@ -533,7 +539,7 @@ void CSceneManager::drawAll()
|
|||
std::sort(TransparentNodeList.begin(), TransparentNodeList.end());
|
||||
|
||||
for (auto &it : TransparentNodeList)
|
||||
it.Node->render();
|
||||
render_node(it.Node);
|
||||
|
||||
TransparentNodeList.clear();
|
||||
}
|
||||
|
@ -546,7 +552,7 @@ void CSceneManager::drawAll()
|
|||
std::sort(TransparentEffectNodeList.begin(), TransparentEffectNodeList.end());
|
||||
|
||||
for (auto &it : TransparentEffectNodeList)
|
||||
it.Node->render();
|
||||
render_node(it.Node);
|
||||
|
||||
TransparentEffectNodeList.clear();
|
||||
}
|
||||
|
@ -557,7 +563,7 @@ void CSceneManager::drawAll()
|
|||
Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0);
|
||||
|
||||
for (auto *node : GuiNodeList)
|
||||
node->render();
|
||||
render_node(node);
|
||||
|
||||
GuiNodeList.clear();
|
||||
}
|
||||
|
|
|
@ -179,6 +179,11 @@ public:
|
|||
//! Set current render time.
|
||||
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
|
||||
bool isCulled(const ISceneNode *node) const override;
|
||||
|
||||
|
@ -268,6 +273,9 @@ private:
|
|||
//! Mesh cache
|
||||
IMeshCache *MeshCache;
|
||||
|
||||
//! Global debug render state
|
||||
u16 DebugDataMask = 0, DebugDataBits = 0;
|
||||
|
||||
E_SCENE_NODE_RENDER_PASS CurrentRenderPass;
|
||||
};
|
||||
|
||||
|
|
|
@ -164,13 +164,6 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters ¶ms
|
|||
ExposedData = ContextManager->getContext();
|
||||
ContextManager->activateContext(ExposedData, false);
|
||||
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);
|
||||
}
|
||||
|
@ -248,6 +241,20 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenS
|
|||
initFeatures();
|
||||
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
|
||||
delete CacheHandler;
|
||||
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);
|
||||
break;
|
||||
case scene::EPT_TRIANGLES:
|
||||
GL.DrawElements((LastMaterial.Wireframe) ? GL_LINES : (LastMaterial.PointCloud) ? GL_POINTS
|
||||
: GL_TRIANGLES,
|
||||
primitiveCount * 3, indexSize, indexList);
|
||||
GL.DrawElements(GL_TRIANGLES, primitiveCount * 3, indexSize, indexList);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -1306,7 +1311,28 @@ void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const S
|
|||
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)
|
||||
GL.LineWidth(core::clamp(static_cast<GLfloat>(material.Thickness), DimAliasedLine[0], DimAliasedLine[1]));
|
||||
|
@ -1615,7 +1641,7 @@ s32 COpenGL3DriverBase::addHighLevelShaderMaterial(
|
|||
s32 nr = -1;
|
||||
COpenGL3MaterialRenderer *r = new COpenGL3MaterialRenderer(
|
||||
this, nr, vertexShaderProgram,
|
||||
pixelShaderProgram,
|
||||
pixelShaderProgram, shaderName,
|
||||
callback, baseMaterial, userData);
|
||||
|
||||
r->drop();
|
||||
|
|
|
@ -161,10 +161,23 @@ public:
|
|||
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 AnisotropicFilterSupported = false;
|
||||
bool BlendMinMaxSupported = false;
|
||||
bool TextureMultisampleSupported = false;
|
||||
bool KHRDebugSupported = false;
|
||||
u32 MaxLabelLength = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver,
|
|||
s32 &outMaterialTypeNr,
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *debugName,
|
||||
IShaderConstantSetCallBack *callback,
|
||||
E_MATERIAL_TYPE baseMaterial,
|
||||
s32 userData) :
|
||||
|
@ -45,7 +46,7 @@ COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver,
|
|||
if (CallBack)
|
||||
CallBack->grab();
|
||||
|
||||
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram);
|
||||
init(outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram, debugName);
|
||||
}
|
||||
|
||||
COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver,
|
||||
|
@ -98,6 +99,7 @@ GLuint COpenGL3MaterialRenderer::getProgram() const
|
|||
void COpenGL3MaterialRenderer::init(s32 &outMaterialTypeNr,
|
||||
const c8 *vertexShaderProgram,
|
||||
const c8 *pixelShaderProgram,
|
||||
const c8 *debugName,
|
||||
bool addMaterial)
|
||||
{
|
||||
outMaterialTypeNr = -1;
|
||||
|
@ -121,6 +123,9 @@ void COpenGL3MaterialRenderer::init(s32 &outMaterialTypeNr,
|
|||
if (!linkProgram())
|
||||
return;
|
||||
|
||||
if (debugName)
|
||||
Driver->irrGlObjectLabel(GL_PROGRAM, Program, debugName);
|
||||
|
||||
if (addMaterial)
|
||||
outMaterialTypeNr = Driver->addMaterialRenderer(this);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
s32 &outMaterialTypeNr,
|
||||
const c8 *vertexShaderProgram = 0,
|
||||
const c8 *pixelShaderProgram = 0,
|
||||
const c8 *debugName = nullptr,
|
||||
IShaderConstantSetCallBack *callback = 0,
|
||||
E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
|
||||
s32 userData = 0);
|
||||
|
@ -66,7 +67,9 @@ protected:
|
|||
E_MATERIAL_TYPE baseMaterial = EMT_SOLID,
|
||||
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 linkProgram();
|
||||
|
|
|
@ -23,8 +23,8 @@ COpenGL3Renderer2D::COpenGL3Renderer2D(const c8 *vertexShaderProgram, const c8 *
|
|||
WithTexture(withTexture)
|
||||
{
|
||||
int Temp = 0;
|
||||
|
||||
init(Temp, vertexShaderProgram, pixelShaderProgram, false);
|
||||
init(Temp, vertexShaderProgram, pixelShaderProgram,
|
||||
withTexture ? "2DTexture" : "2DNoTexture", false);
|
||||
|
||||
COpenGL3CacheHandler *cacheHandler = Driver->getCacheHandler();
|
||||
|
||||
|
|
|
@ -72,6 +72,9 @@ void COpenGL3Driver::initFeatures()
|
|||
LODBiasSupported = true;
|
||||
BlendMinMaxSupported = true;
|
||||
TextureMultisampleSupported = true;
|
||||
KHRDebugSupported = isVersionAtLeast(4, 6) || queryExtension("GL_KHR_debug");
|
||||
if (KHRDebugSupported)
|
||||
MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH);
|
||||
|
||||
// COGLESCoreExtensionHandler::Feature
|
||||
static_assert(MATERIAL_MAX_TEXTURES <= 16, "Only up to 16 textures are guaranteed");
|
||||
|
|
|
@ -124,6 +124,9 @@ void COpenGLES2Driver::initFeatures()
|
|||
AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic");
|
||||
BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax];
|
||||
TextureMultisampleSupported = isVersionAtLeast(3, 1);
|
||||
KHRDebugSupported = queryExtension("GL_KHR_debug");
|
||||
if (KHRDebugSupported)
|
||||
MaxLabelLength = GetInteger(GL.MAX_LABEL_LENGTH);
|
||||
|
||||
// COGLESCoreExtensionHandler::Feature
|
||||
static_assert(MATERIAL_MAX_TEXTURES <= 8, "Only up to 8 textures are guaranteed");
|
||||
|
|
|
@ -417,7 +417,6 @@ set(independent_SRCS
|
|||
hud.cpp
|
||||
inventory.cpp
|
||||
itemstackmetadata.cpp
|
||||
lighting.cpp
|
||||
log.cpp
|
||||
metadata.cpp
|
||||
modchannels.cpp
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "debug.h"
|
||||
#include "util/container.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "util/basic_macros.h"
|
||||
|
|
|
@ -112,7 +112,8 @@ public:
|
|||
|
||||
void resize(u32 scrollback);
|
||||
|
||||
protected:
|
||||
// Get the current scroll position
|
||||
s32 getScrollPosition() const { return m_scroll; }
|
||||
s32 getTopScrollPos() const;
|
||||
s32 getBottomScrollPos() const;
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "util/container.h"
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include "irrlichttypes.h"
|
||||
#include "util/container.h" // MutexedQueue
|
||||
#include <string>
|
||||
|
||||
enum ChatEventType {
|
||||
CET_CHAT,
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "profiler.h"
|
||||
#include "shader.h"
|
||||
#include "gettext.h"
|
||||
#include "gettime.h"
|
||||
#include "clientdynamicinfo.h"
|
||||
#include "clientmap.h"
|
||||
#include "clientmedia.h"
|
||||
|
|
|
@ -91,8 +91,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
|||
init_args(start_data, cmd_args);
|
||||
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound"))
|
||||
g_sound_manager_singleton = createSoundManagerSingleton();
|
||||
g_sound_manager_singleton = createSoundManagerSingleton();
|
||||
#endif
|
||||
|
||||
if (!init_engine())
|
||||
|
|
|
@ -445,8 +445,8 @@ void Clouds::readSettings()
|
|||
// chosen to avoid exactly that.
|
||||
// refer to vertex_count in updateMesh()
|
||||
m_enable_3d = g_settings->getBool("enable_3d_clouds");
|
||||
const u16 maximum = m_enable_3d ? 62 : 25;
|
||||
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum);
|
||||
const u16 maximum = !m_enable_3d ? 62 : 25;
|
||||
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 8, maximum);
|
||||
|
||||
invalidateMesh();
|
||||
}
|
||||
|
|
|
@ -656,25 +656,33 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
|||
}
|
||||
} else if (m_prop.visual == "upright_sprite") {
|
||||
grabMatrixNode();
|
||||
scene::SMesh *mesh = new scene::SMesh();
|
||||
double dx = BS * m_prop.visual_size.X / 2;
|
||||
double dy = BS * m_prop.visual_size.Y / 2;
|
||||
auto mesh = make_irr<scene::SMesh>();
|
||||
f32 dx = BS * m_prop.visual_size.X / 2;
|
||||
f32 dy = BS * m_prop.visual_size.Y / 2;
|
||||
video::SColor c(0xFFFFFFFF);
|
||||
|
||||
{ // Front
|
||||
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;
|
||||
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 (auto &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);
|
||||
|
||||
// Set material
|
||||
|
@ -682,36 +690,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
|||
buf->getMaterial().ColorParam = c;
|
||||
|
||||
// Add to mesh
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
mesh->addMeshBuffer(buf.get());
|
||||
}
|
||||
{ // 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
|
||||
setMaterial(buf->getMaterial());
|
||||
buf->getMaterial().ColorParam = c;
|
||||
|
||||
// Add to mesh
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
}
|
||||
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
|
||||
mesh->recalculateBoundingBox();
|
||||
m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode);
|
||||
m_meshnode->grab();
|
||||
mesh->drop();
|
||||
} else if (m_prop.visual == "cube") {
|
||||
grabMatrixNode();
|
||||
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
|
||||
|
|
|
@ -4,15 +4,23 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "clientobject.h"
|
||||
#include "EMaterialTypes.h"
|
||||
#include "IDummyTransformationSceneNode.h"
|
||||
#include "irrlichttypes.h"
|
||||
|
||||
#include "object_properties.h"
|
||||
#include "itemgroup.h"
|
||||
#include "clientobject.h"
|
||||
#include "constants.h"
|
||||
#include "itemgroup.h"
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace irr::scene {
|
||||
class IMeshSceneNode;
|
||||
class IBillboardSceneNode;
|
||||
}
|
||||
|
||||
class Camera;
|
||||
class Client;
|
||||
struct Nametag;
|
||||
|
|
|
@ -62,46 +62,44 @@ const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_railli
|
|||
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output):
|
||||
data(input),
|
||||
collector(output),
|
||||
nodedef(data->nodedef),
|
||||
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE),
|
||||
smooth_liquids(g_settings->getBool("enable_water_reflections"))
|
||||
nodedef(data->m_nodedef),
|
||||
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
getTile(index, &cur_node.tile);
|
||||
if (!data->m_smooth_lighting)
|
||||
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
|
||||
getTile(index, tile_ret);
|
||||
|
||||
for (auto &layer : cur_node.tile.layers) {
|
||||
for (auto &layer : tile_ret->layers) {
|
||||
layer.material_flags |= set_flags;
|
||||
layer.material_flags &= ~reset_flags;
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
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.
|
||||
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;
|
||||
|
||||
for (auto &layernum : tile->layers) {
|
||||
for (auto &layernum : tile_ret->layers) {
|
||||
TileLayer *layer = &layernum;
|
||||
if (layer->texture_id == 0)
|
||||
continue;
|
||||
|
@ -114,7 +112,7 @@ void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply
|
|||
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)
|
||||
{
|
||||
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)
|
||||
vertices[j].Color = blendLightColor(coords[j]);
|
||||
else
|
||||
vertices[j].Color = cur_node.color;
|
||||
vertices[j].Color = cur_node.lcolor;
|
||||
if (shade_face)
|
||||
applyFacesShading(vertices[j].Color, normal2);
|
||||
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 max = box.MaxEdge;
|
||||
|
||||
|
@ -218,7 +218,7 @@ enum class QuadDiagonal {
|
|||
// and to choose diagonal to split the quad at.
|
||||
template <typename Fn>
|
||||
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
|
||||
|
||||
|
@ -238,16 +238,16 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
|
|||
void MapblockMeshGenerator::getSmoothLightFrame()
|
||||
{
|
||||
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) {
|
||||
LightPair light(getSmoothLightTransparent(blockpos_nodes + cur_node.p, light_dirs[k], data));
|
||||
cur_node.frame.lightsDay[k] = light.lightDay;
|
||||
cur_node.frame.lightsNight[k] = light.lightNight;
|
||||
cur_node.lframe.lightsDay[k] = light.lightDay;
|
||||
cur_node.lframe.lightsNight[k] = light.lightNight;
|
||||
// If there is direct sunlight and no ambient occlusion at some corner,
|
||||
// mark the vertical edge (top and bottom corners) containing it.
|
||||
if (light.lightDay == 255) {
|
||||
cur_node.frame.sunlight[k] = true;
|
||||
cur_node.frame.sunlight[k ^ 2] = true;
|
||||
cur_node.lframe.sunlight[k] = 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 dz = (k & 1) ? z : 1 - z;
|
||||
// Use direct sunlight (255), if any; use daylight otherwise.
|
||||
f32 light_boosted = cur_node.frame.sunlight[k] ? 255 : cur_node.frame.lightsDay[k];
|
||||
lightDay += dx * dy * dz * cur_node.frame.lightsDay[k];
|
||||
lightNight += dx * dy * dz * cur_node.frame.lightsNight[k];
|
||||
f32 light_boosted = cur_node.lframe.sunlight[k] ? 255 : cur_node.lframe.lightsDay[k];
|
||||
lightDay += dx * dy * dz * cur_node.lframe.lightsDay[k];
|
||||
lightNight += dx * dy * dz * cur_node.lframe.lightsNight[k];
|
||||
lightBoosted += dx * dy * dz * light_boosted;
|
||||
}
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
||||
TileSpec *tiles, int tile_count, u8 mask)
|
||||
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const TileSpec &tile,
|
||||
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;
|
||||
f32 texture_coord_buf[24];
|
||||
|
@ -348,10 +353,6 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
|||
generateCuboidTextureCoords(box, texture_coord_buf);
|
||||
txc = texture_coord_buf;
|
||||
}
|
||||
if (!tiles) {
|
||||
tiles = &cur_node.tile;
|
||||
tile_count = 1;
|
||||
}
|
||||
if (data->m_smooth_lighting) {
|
||||
LightInfo lights[8];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
|
@ -377,7 +378,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
|||
});
|
||||
} else {
|
||||
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)
|
||||
applyFacesShading(color, vertices[0].Normal);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
|
@ -540,19 +541,20 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing()
|
|||
if (data->m_smooth_lighting)
|
||||
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 this liquid emits light and doesn't contain light, draw
|
||||
// it at what it emits, for an increased effect
|
||||
u8 e = decode_light(cur_node.f->light_source);
|
||||
cur_node.light = LightPair(std::max(e, cur_node.light.lightDay),
|
||||
std::max(e, cur_node.light.lightNight));
|
||||
light = LightPair(std::max(e, light.lightDay),
|
||||
std::max(e, light.lightNight));
|
||||
} else if (nodedef->getLightingFlags(ntop).has_light) {
|
||||
// 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_node.color = encode_light(cur_node.light, cur_node.f->light_source);
|
||||
cur_liquid.color_top = encode_light(light, cur_node.f->light_source);
|
||||
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::getLiquidNeighborhood()
|
||||
|
@ -695,10 +697,18 @@ void MapblockMeshGenerator::drawLiquidSides()
|
|||
v += 0.5f - cur_liquid.corner_levels[base.Z][base.X];
|
||||
}
|
||||
|
||||
video::SColor color;
|
||||
if (data->m_smooth_lighting)
|
||||
cur_node.color = blendLightColor(pos);
|
||||
color = blendLightColor(pos);
|
||||
else
|
||||
color = cur_node.lcolor;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -722,7 +732,7 @@ void MapblockMeshGenerator::drawLiquidTop()
|
|||
int u = corner_resolve[i][0];
|
||||
int w = corner_resolve[i][1];
|
||||
|
||||
if (smooth_liquids) {
|
||||
if (data->m_enable_water_reflections) {
|
||||
int x = vertices[i].Pos.X > 0;
|
||||
int z = vertices[i].Pos.Z > 0;
|
||||
|
||||
|
@ -774,7 +784,7 @@ void MapblockMeshGenerator::drawLiquidTop()
|
|||
|
||||
vertex.TCoords += tcoord_translate;
|
||||
|
||||
if (!smooth_liquids) {
|
||||
if (!data->m_enable_water_reflections) {
|
||||
vertex.Normal = v3f(dx, 1., dz).normalize();
|
||||
}
|
||||
}
|
||||
|
@ -816,7 +826,8 @@ void MapblockMeshGenerator::drawLiquidNode()
|
|||
|
||||
void MapblockMeshGenerator::drawGlasslikeNode()
|
||||
{
|
||||
useTile(0, 0, 0);
|
||||
TileSpec tile;
|
||||
useTile(&tile, 0, 0, 0);
|
||||
|
||||
for (int face = 0; face < 6; face++) {
|
||||
// Check this neighbor
|
||||
|
@ -850,7 +861,7 @@ void MapblockMeshGenerator::drawGlasslikeNode()
|
|||
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++)
|
||||
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];
|
||||
for (auto &glass_tile : glass_tiles)
|
||||
glass_tile = tiles[4];
|
||||
|
@ -934,7 +942,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
{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++) {
|
||||
bool edge_invisible;
|
||||
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]];
|
||||
if (edge_invisible)
|
||||
continue;
|
||||
drawAutoLightedCuboid(frame_edges[edge]);
|
||||
drawAutoLightedCuboid(frame_edges[edge], tiles[1]);
|
||||
}
|
||||
|
||||
for (int face = 0; face < 6; face++) {
|
||||
if (nb[face])
|
||||
continue;
|
||||
|
||||
cur_node.tile = glass_tiles[face];
|
||||
// Face at Z-
|
||||
v3f vertices[4] = {
|
||||
v3f(-a, a, -g),
|
||||
|
@ -976,7 +982,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
}
|
||||
}
|
||||
v3s16 dir = g_6dirs[face];
|
||||
drawQuad(vertices, dir);
|
||||
drawQuad(glass_tiles[face], vertices, dir);
|
||||
}
|
||||
|
||||
// Optionally render internal liquid level defined by param2
|
||||
|
@ -986,13 +992,18 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
// Internal liquid level has param2 range 0 .. 63,
|
||||
// convert it to -0.5 .. 0.5
|
||||
float vlev = (param2 / 63.0f) * 2.0f - 1.0f;
|
||||
getSpecialTile(0, &cur_node.tile);
|
||||
drawAutoLightedCuboid(aabb3f(-(nb[5] ? g : b),
|
||||
-(nb[4] ? g : b),
|
||||
-(nb[3] ? g : b),
|
||||
(nb[2] ? g : b),
|
||||
(nb[1] ? g : b) * vlev,
|
||||
(nb[0] ? g : b)));
|
||||
TileSpec tile;
|
||||
getSpecialTile(0, &tile);
|
||||
drawAutoLightedCuboid(
|
||||
aabb3f(
|
||||
-(nb[5] ? g : b),
|
||||
-(nb[4] ? 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
|
||||
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;
|
||||
v3f vertices[4] = {
|
||||
|
@ -1054,13 +1066,14 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
|||
break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawSignlikeNode()
|
||||
{
|
||||
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;
|
||||
float size = BS / 2 * cur_node.f->visual_scale;
|
||||
// Wall at X+ of node
|
||||
|
@ -1091,13 +1104,13 @@ void MapblockMeshGenerator::drawSignlikeNode()
|
|||
vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
|
||||
bool offset_top_only)
|
||||
void MapblockMeshGenerator::drawPlantlikeQuad(const TileSpec &tile,
|
||||
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(-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_node.scale = BS / 2 * cur_node.f->visual_scale;
|
||||
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.random_offset_Y = false;
|
||||
cur_plant.face_num = 0;
|
||||
|
@ -1164,7 +1177,7 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
|
|||
case CPT2_MESHOPTIONS:
|
||||
cur_plant.draw_style = PlantlikeStyle(cur_node.n.param2 & MO_MASK_STYLE);
|
||||
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) {
|
||||
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);
|
||||
|
@ -1205,63 +1218,66 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
|
|||
|
||||
switch (cur_plant.draw_style) {
|
||||
case PLANT_STYLE_CROSS:
|
||||
drawPlantlikeQuad(46);
|
||||
drawPlantlikeQuad(-44);
|
||||
drawPlantlikeQuad(tile, 46);
|
||||
drawPlantlikeQuad(tile, -44);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_CROSS2:
|
||||
drawPlantlikeQuad(91);
|
||||
drawPlantlikeQuad(1);
|
||||
drawPlantlikeQuad(tile, 91);
|
||||
drawPlantlikeQuad(tile, 1);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_STAR:
|
||||
drawPlantlikeQuad(121);
|
||||
drawPlantlikeQuad(241);
|
||||
drawPlantlikeQuad(1);
|
||||
drawPlantlikeQuad(tile, 121);
|
||||
drawPlantlikeQuad(tile, 241);
|
||||
drawPlantlikeQuad(tile, 1);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_HASH:
|
||||
drawPlantlikeQuad( 1, BS / 4);
|
||||
drawPlantlikeQuad( 91, BS / 4);
|
||||
drawPlantlikeQuad(181, BS / 4);
|
||||
drawPlantlikeQuad(271, BS / 4);
|
||||
drawPlantlikeQuad(tile, 1, BS / 4);
|
||||
drawPlantlikeQuad(tile, 91, BS / 4);
|
||||
drawPlantlikeQuad(tile, 181, BS / 4);
|
||||
drawPlantlikeQuad(tile, 271, BS / 4);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_HASH2:
|
||||
drawPlantlikeQuad( 1, -BS / 2, true);
|
||||
drawPlantlikeQuad( 91, -BS / 2, true);
|
||||
drawPlantlikeQuad(181, -BS / 2, true);
|
||||
drawPlantlikeQuad(271, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 1, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 91, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 181, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 271, -BS / 2, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawPlantlikeNode()
|
||||
{
|
||||
useTile();
|
||||
drawPlantlike();
|
||||
TileSpec tile;
|
||||
useTile(&tile);
|
||||
drawPlantlike(tile);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawPlantlikeRootedNode()
|
||||
{
|
||||
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.p.Y++;
|
||||
if (data->m_smooth_lighting) {
|
||||
getSmoothLightFrame();
|
||||
} else {
|
||||
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--;
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle,
|
||||
float offset_h, float offset_v)
|
||||
void MapblockMeshGenerator::drawFirelikeQuad(const TileSpec &tile, float rotation,
|
||||
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(-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.Y += offset_v;
|
||||
}
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawFirelikeNode()
|
||||
{
|
||||
useTile();
|
||||
cur_node.scale = BS / 2 * cur_node.f->visual_scale;
|
||||
TileSpec tile;
|
||||
useTile(&tile);
|
||||
|
||||
// Check for adjacent nodes
|
||||
bool neighbors = false;
|
||||
|
@ -1300,41 +1316,41 @@ void MapblockMeshGenerator::drawFirelikeNode()
|
|||
bool drawBottomFire = neighbor[D6D_YP];
|
||||
|
||||
if (drawBasicFire || neighbor[D6D_ZP])
|
||||
drawFirelikeQuad(0, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 0, -10, 0.4 * BS);
|
||||
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])
|
||||
drawFirelikeQuad(90, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 90, -10, 0.4 * BS);
|
||||
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])
|
||||
drawFirelikeQuad(180, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 180, -10, 0.4 * BS);
|
||||
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])
|
||||
drawFirelikeQuad(270, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 270, -10, 0.4 * BS);
|
||||
else if (drawBottomFire)
|
||||
drawFirelikeQuad(270, 70, 0.47 * BS, 0.484 * BS);
|
||||
drawFirelikeQuad(tile, 270, 70, 0.47 * BS, 0.484 * BS);
|
||||
|
||||
if (drawBasicFire) {
|
||||
drawFirelikeQuad(45, 0, 0.0);
|
||||
drawFirelikeQuad(-45, 0, 0.0);
|
||||
drawFirelikeQuad(tile, 45, 0, 0.0);
|
||||
drawFirelikeQuad(tile, -45, 0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawFencelikeNode()
|
||||
{
|
||||
useTile(0, 0, 0);
|
||||
TileSpec tile_nocrack = cur_node.tile;
|
||||
TileSpec tile_nocrack;
|
||||
useTile(&tile_nocrack, 0, 0, 0);
|
||||
|
||||
for (auto &layer : tile_nocrack.layers)
|
||||
layer.material_flags &= ~MATERIAL_FLAG_CRACK;
|
||||
|
||||
// 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;
|
||||
|
||||
static const f32 post_rad = BS / 8;
|
||||
|
@ -1352,10 +1368,7 @@ void MapblockMeshGenerator::drawFencelikeNode()
|
|||
0.500, 0.000, 0.750, 1.000,
|
||||
0.750, 0.000, 1.000, 1.000,
|
||||
};
|
||||
cur_node.tile = tile_rot;
|
||||
drawAutoLightedCuboid(post, postuv);
|
||||
|
||||
cur_node.tile = tile_nocrack;
|
||||
drawAutoLightedCuboid(post, tile_rot, postuv);
|
||||
|
||||
// Now a section of fence, +X, if there's a post there
|
||||
v3s16 p2 = cur_node.p;
|
||||
|
@ -1375,8 +1388,8 @@ void MapblockMeshGenerator::drawFencelikeNode()
|
|||
0.000, 0.500, 1.000, 0.625,
|
||||
0.000, 0.875, 1.000, 1.000,
|
||||
};
|
||||
drawAutoLightedCuboid(bar_x1, xrailuv);
|
||||
drawAutoLightedCuboid(bar_x2, xrailuv);
|
||||
drawAutoLightedCuboid(bar_x1, tile_nocrack, xrailuv);
|
||||
drawAutoLightedCuboid(bar_x2, tile_nocrack, xrailuv);
|
||||
}
|
||||
|
||||
// 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.6250, 0.6250, 0.7500, 0.7500,
|
||||
};
|
||||
drawAutoLightedCuboid(bar_z1, zrailuv);
|
||||
drawAutoLightedCuboid(bar_z2, zrailuv);
|
||||
drawAutoLightedCuboid(bar_z1, tile_nocrack, zrailuv);
|
||||
drawAutoLightedCuboid(bar_z2, tile_nocrack, zrailuv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1480,7 +1493,8 @@ void MapblockMeshGenerator::drawRaillikeNode()
|
|||
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 size = BS / 2;
|
||||
|
@ -1494,7 +1508,7 @@ void MapblockMeshGenerator::drawRaillikeNode()
|
|||
if (angle)
|
||||
for (v3f &vertex : vertices)
|
||||
vertex.rotateXZBy(angle);
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1526,7 +1540,7 @@ void MapblockMeshGenerator::drawAllfacesNode()
|
|||
getTile(nodebox_tile_dirs[face], &tiles[face]);
|
||||
if (data->m_smooth_lighting)
|
||||
getSmoothLightFrame();
|
||||
drawAutoLightedCuboid(box, nullptr, tiles, 6);
|
||||
drawAutoLightedCuboid(box, tiles, 6);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawNodeboxNode()
|
||||
|
@ -1633,7 +1647,7 @@ void MapblockMeshGenerator::drawNodeboxNode()
|
|||
|
||||
for (auto &box : boxes) {
|
||||
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++) {
|
||||
// Only up to 6 tiles are supported
|
||||
const u32 tile = mesh->getTextureSlot(j);
|
||||
useTile(MYMIN(tile, 5));
|
||||
const u32 tile_idx = mesh->getTextureSlot(j);
|
||||
TileSpec tile;
|
||||
useTile(&tile, MYMIN(tile_idx, 5));
|
||||
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
|
||||
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) {
|
||||
// Mesh is always private here. So the lighting is applied to each
|
||||
// vertex right here.
|
||||
for (u32 k = 0; k < vertex_count; k++) {
|
||||
video::S3DVertex &vertex = vertices[k];
|
||||
vertex.Color = blendLightColor(vertex.Pos, vertex.Normal);
|
||||
vertex.Pos += cur_node.origin;
|
||||
}
|
||||
collector->append(cur_node.tile, vertices, vertex_count,
|
||||
buf->getIndices(), buf->getIndexCount());
|
||||
} else {
|
||||
// Let the collector process colors, etc.
|
||||
collector->append(cur_node.tile, vertices, vertex_count,
|
||||
buf->getIndices(), buf->getIndexCount(), cur_node.origin,
|
||||
cur_node.color, cur_node.f->light_source);
|
||||
bool is_light_source = cur_node.f->light_source != 0;
|
||||
for (u32 k = 0; k < vertex_count; k++) {
|
||||
video::S3DVertex &vertex = vertices[k];
|
||||
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();
|
||||
}
|
||||
|
@ -1725,10 +1745,12 @@ void MapblockMeshGenerator::drawNode()
|
|||
break;
|
||||
}
|
||||
cur_node.origin = intToFloat(cur_node.p, BS);
|
||||
if (data->m_smooth_lighting)
|
||||
if (data->m_smooth_lighting) {
|
||||
getSmoothLightFrame();
|
||||
else
|
||||
cur_node.light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
|
||||
} else {
|
||||
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) {
|
||||
case NDT_FLOWINGLIQUID: drawLiquidNode(); break;
|
||||
case NDT_GLASSLIKE: drawGlasslikeNode(); break;
|
||||
|
@ -1751,19 +1773,11 @@ void MapblockMeshGenerator::generate()
|
|||
{
|
||||
ZoneScoped;
|
||||
|
||||
for (cur_node.p.Z = 0; cur_node.p.Z < data->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.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) {
|
||||
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->m_side_length; cur_node.p.Y++)
|
||||
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.f = &nodedef->get(cur_node.n);
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ class MapblockMeshGenerator
|
|||
public:
|
||||
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
|
||||
void generate();
|
||||
void renderSingle(content_t node, u8 param2 = 0x00);
|
||||
|
||||
private:
|
||||
MeshMakeData *const data;
|
||||
|
@ -59,15 +58,12 @@ private:
|
|||
|
||||
// current node
|
||||
struct {
|
||||
v3s16 p;
|
||||
v3f origin;
|
||||
v3s16 p; // relative to blockpos_nodes
|
||||
v3f origin; // p in BS space
|
||||
MapNode n;
|
||||
const ContentFeatures *f;
|
||||
LightPair light;
|
||||
LightFrame frame;
|
||||
video::SColor color;
|
||||
TileSpec tile;
|
||||
f32 scale;
|
||||
LightFrame lframe; // smooth lighting
|
||||
video::SColor lcolor; // unsmooth lighting
|
||||
} cur_node;
|
||||
|
||||
// lighting
|
||||
|
@ -76,21 +72,23 @@ private:
|
|||
video::SColor blendLightColor(const v3f &vertex_pos);
|
||||
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);
|
||||
void getTile(int index, TileSpec *tile);
|
||||
void getTile(v3s16 direction, TileSpec *tile);
|
||||
void getSpecialTile(int index, TileSpec *tile, bool apply_crack = false);
|
||||
void getTile(int index, TileSpec *tile_ret);
|
||||
void getTile(v3s16 direction, TileSpec *tile_ret);
|
||||
void getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack = false);
|
||||
|
||||
// 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);
|
||||
|
||||
// cuboid drawing!
|
||||
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 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;
|
||||
|
||||
// liquid-specific
|
||||
|
@ -113,7 +111,6 @@ private:
|
|||
f32 corner_levels[2][2];
|
||||
};
|
||||
LiquidData cur_liquid;
|
||||
bool smooth_liquids = false;
|
||||
|
||||
void prepareLiquidNodeDrawing();
|
||||
void getLiquidNeighborhood();
|
||||
|
@ -136,6 +133,7 @@ private:
|
|||
struct PlantlikeData {
|
||||
PlantlikeStyle draw_style;
|
||||
v3f offset;
|
||||
float scale;
|
||||
float rotate_degree;
|
||||
bool random_offset_Y;
|
||||
int face_num;
|
||||
|
@ -143,12 +141,12 @@ private:
|
|||
};
|
||||
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);
|
||||
void drawPlantlike(bool is_rooted = false);
|
||||
void drawPlantlike(const TileSpec &tile, bool is_rooted = false);
|
||||
|
||||
// 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);
|
||||
|
||||
// drawtypes
|
||||
|
|
|
@ -472,6 +472,8 @@ public:
|
|||
|
||||
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
|
||||
* 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
|
||||
|
@ -680,6 +682,8 @@ protected:
|
|||
private:
|
||||
struct Flags {
|
||||
bool disable_camera_update = false;
|
||||
/// 0 = no debug text active, see toggleDebug() for the rest
|
||||
int debug_state = 0;
|
||||
};
|
||||
|
||||
void pauseAnimation();
|
||||
|
@ -782,11 +786,8 @@ private:
|
|||
* (as opposed to the this local caching). This can be addressed in
|
||||
* a later release.
|
||||
*/
|
||||
bool m_cache_disable_escape_sequences;
|
||||
bool m_cache_doubletap_jump;
|
||||
bool m_cache_enable_clouds;
|
||||
bool m_cache_enable_joysticks;
|
||||
bool m_cache_enable_particles;
|
||||
bool m_cache_enable_fog;
|
||||
bool m_cache_enable_noclip;
|
||||
bool m_cache_enable_free_move;
|
||||
|
@ -828,16 +829,10 @@ Game::Game() :
|
|||
{
|
||||
g_settings->registerChangedCallback("chat_log_level",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("disable_escape_sequences",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("doubletap_jump",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_clouds",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_joysticks",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_particles",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_fog",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("mouse_sensitivity",
|
||||
|
@ -937,6 +932,10 @@ bool Game::startup(bool *kill,
|
|||
runData.time_from_last_punch = 10.0;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -1175,7 +1174,7 @@ bool Game::init(
|
|||
bool Game::initSound()
|
||||
{
|
||||
#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;
|
||||
sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
|
||||
std::make_unique<SoundFallbackPathProvider>());
|
||||
|
@ -1333,8 +1332,7 @@ bool Game::createClient(const GameStartData &start_data)
|
|||
|
||||
/* Clouds
|
||||
*/
|
||||
if (m_cache_enable_clouds)
|
||||
clouds = make_irr<Clouds>(smgr, shader_src, -1, rand());
|
||||
clouds = make_irr<Clouds>(smgr, shader_src, -1, myrand());
|
||||
|
||||
/* Skybox
|
||||
*/
|
||||
|
@ -1708,6 +1706,7 @@ void Game::updateDebugState()
|
|||
hud->disableBlockBounds();
|
||||
if (!has_debug) {
|
||||
draw_control->show_wireframe = false;
|
||||
smgr->setGlobalDebugData(0, bbox_debug_flag);
|
||||
m_flags.disable_camera_update = false;
|
||||
m_game_formspec.disableDebugView();
|
||||
}
|
||||
|
@ -1845,7 +1844,9 @@ void Game::processUserInput(f32 dtime)
|
|||
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();
|
||||
}
|
||||
|
||||
|
@ -1909,34 +1910,22 @@ void Game::processKeyInput()
|
|||
toggleNoClip();
|
||||
#if USE_SOUND
|
||||
} else if (wasKeyDown(KeyType::MUTE)) {
|
||||
if (g_settings->getBool("enable_sound")) {
|
||||
bool new_mute_sound = !g_settings->getBool("mute_sound");
|
||||
g_settings->setBool("mute_sound", new_mute_sound);
|
||||
if (new_mute_sound)
|
||||
m_game_ui->showTranslatedStatusText("Sound muted");
|
||||
else
|
||||
m_game_ui->showTranslatedStatusText("Sound unmuted");
|
||||
} else {
|
||||
m_game_ui->showTranslatedStatusText("Sound system is disabled");
|
||||
}
|
||||
bool new_mute_sound = !g_settings->getBool("mute_sound");
|
||||
g_settings->setBool("mute_sound", new_mute_sound);
|
||||
if (new_mute_sound)
|
||||
m_game_ui->showTranslatedStatusText("Sound muted");
|
||||
else
|
||||
m_game_ui->showTranslatedStatusText("Sound unmuted");
|
||||
} 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;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
} else {
|
||||
m_game_ui->showTranslatedStatusText("Sound system is disabled");
|
||||
}
|
||||
float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
} 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;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
} else {
|
||||
m_game_ui->showTranslatedStatusText("Sound system is disabled");
|
||||
}
|
||||
float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
#else
|
||||
} else if (wasKeyDown(KeyType::MUTE) || wasKeyDown(KeyType::INC_VOLUME)
|
||||
|| wasKeyDown(KeyType::DEC_VOLUME)) {
|
||||
|
@ -2267,45 +2256,44 @@ void Game::toggleDebug()
|
|||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||
bool has_debug = client->checkPrivilege("debug");
|
||||
bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
|
||||
|
||||
// Initial: No debug info
|
||||
// 1x toggle: Debug text
|
||||
// 2x toggle: Debug text with profiler graph
|
||||
// 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.
|
||||
// * Minimal: Only technical client info that not gameplay-relevant
|
||||
// * Basic: Info that might give gameplay advantage, e.g. pos, angle
|
||||
// Basic mode is used when player has the debug HUD flag set,
|
||||
// otherwise the Minimal mode is used.
|
||||
if (!m_game_ui->m_flags.show_minimal_debug) {
|
||||
m_game_ui->m_flags.show_minimal_debug = true;
|
||||
if (has_basic_debug)
|
||||
m_game_ui->m_flags.show_basic_debug = true;
|
||||
m_game_ui->m_flags.show_profiler_graph = false;
|
||||
draw_control->show_wireframe = false;
|
||||
|
||||
auto &state = m_flags.debug_state;
|
||||
state = (state + 1) % 5;
|
||||
if (state >= 3 && !has_debug)
|
||||
state = 0;
|
||||
|
||||
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");
|
||||
} else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) {
|
||||
if (has_basic_debug)
|
||||
m_game_ui->m_flags.show_basic_debug = true;
|
||||
m_game_ui->m_flags.show_profiler_graph = true;
|
||||
} else if (state == 2) {
|
||||
m_game_ui->showTranslatedStatusText("Profiler graph shown");
|
||||
} else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
|
||||
if (has_basic_debug)
|
||||
m_game_ui->m_flags.show_basic_debug = true;
|
||||
m_game_ui->m_flags.show_profiler_graph = false;
|
||||
draw_control->show_wireframe = true;
|
||||
m_game_ui->showTranslatedStatusText("Wireframe shown");
|
||||
} else if (state == 3) {
|
||||
if (driver->getDriverType() == video::EDT_OGLES2)
|
||||
m_game_ui->showTranslatedStatusText("Wireframe not supported by video driver");
|
||||
else
|
||||
m_game_ui->showTranslatedStatusText("Wireframe shown");
|
||||
} else if (state == 4) {
|
||||
m_game_ui->showTranslatedStatusText("Bounding boxes shown");
|
||||
} else {
|
||||
m_game_ui->m_flags.show_minimal_debug = false;
|
||||
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");
|
||||
}
|
||||
m_game_ui->showTranslatedStatusText("All debug info hidden");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2896,9 +2884,6 @@ void Game::handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
|
|||
|
||||
void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam)
|
||||
{
|
||||
if (!clouds)
|
||||
return;
|
||||
|
||||
clouds->setDensity(event->cloud_params.density);
|
||||
clouds->setColorBright(video::SColor(event->cloud_params.color_bright));
|
||||
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();
|
||||
for (const auto& entry : entries) {
|
||||
std::string line;
|
||||
if (!m_cache_disable_escape_sequences) {
|
||||
line.append(color_for(entry.level));
|
||||
}
|
||||
line.append(entry.combined);
|
||||
line.append(color_for(entry.level)).append(entry.combined);
|
||||
chat_backend->addMessage(L"", utf8_to_wide(line));
|
||||
}
|
||||
|
||||
|
@ -3023,8 +3005,7 @@ void Game::updateCamera(f32 dtime)
|
|||
client->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 {
|
||||
runData.dig_time_complete = params.time;
|
||||
|
||||
if (m_cache_enable_particles) {
|
||||
client->getParticleManager()->addNodeParticle(client,
|
||||
player, nodepos, n, features);
|
||||
}
|
||||
client->getParticleManager()->addNodeParticle(client,
|
||||
player, nodepos, n, features);
|
||||
}
|
||||
|
||||
if (!runData.digging) {
|
||||
|
@ -3771,11 +3750,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
|
|||
|
||||
client->interact(INTERACT_DIGGING_COMPLETED, pointed);
|
||||
|
||||
if (m_cache_enable_particles) {
|
||||
client->getParticleManager()->addDiggingParticles(client,
|
||||
player, nodepos, n, features);
|
||||
}
|
||||
|
||||
client->getParticleManager()->addDiggingParticles(client,
|
||||
player, nodepos, n, features);
|
||||
|
||||
// Send event to trigger sound
|
||||
client->getEventManager()->put(new NodeDugEvent(nodepos, n));
|
||||
|
@ -3866,8 +3842,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||
/*
|
||||
Update clouds
|
||||
*/
|
||||
if (clouds)
|
||||
updateClouds(dtime);
|
||||
updateClouds(dtime);
|
||||
|
||||
/*
|
||||
Update particles
|
||||
|
@ -4129,11 +4104,8 @@ void Game::readSettings()
|
|||
}
|
||||
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_enable_clouds = g_settings->getBool("enable_clouds");
|
||||
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_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);
|
||||
|
|
|
@ -333,12 +333,11 @@ void GameFormSpec::showPauseMenu()
|
|||
|
||||
#ifndef __ANDROID__
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound")) {
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
|
||||
<< strgettext("Sound Volume") << "]";
|
||||
}
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
|
||||
<< strgettext("Sound Volume") << "]";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (g_touchcontrols) {
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;"
|
||||
<< strgettext("Touchscreen Layout") << "]";
|
||||
|
|
|
@ -215,7 +215,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
|||
void GameUI::initFlags()
|
||||
{
|
||||
m_flags = GameUI::Flags();
|
||||
m_flags.show_minimal_debug = g_settings->getBool("show_debug");
|
||||
}
|
||||
|
||||
void GameUI::showTranslatedStatusText(const char *str)
|
||||
|
|
|
@ -94,8 +94,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
|
|||
auto it_img = g_imgCache.find(origname);
|
||||
video::IImage *srcimg = (it_img != g_imgCache.end()) ? it_img->second : nullptr;
|
||||
if (!srcimg) {
|
||||
if (!g_settings->getBool("gui_scaling_filter_txr2img"))
|
||||
return src;
|
||||
// Download image from GPU
|
||||
srcimg = driver->createImageFromData(src->getColorFormat(),
|
||||
src->getSize(), src->lock(video::ETLM_READ_ONLY), false);
|
||||
src->unlock();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "irrlichttypes.h"
|
||||
#include "irr_v2d.h"
|
||||
#include "joystick_controller.h"
|
||||
#include <list>
|
||||
#include "keycode.h"
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include <IEventReceiver.h>
|
||||
#include "irrlichttypes.h"
|
||||
|
||||
#include "keys.h"
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
|
|
@ -26,10 +26,14 @@
|
|||
MeshMakeData
|
||||
*/
|
||||
|
||||
MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length):
|
||||
side_length(side_length),
|
||||
nodedef(ndef)
|
||||
{}
|
||||
MeshMakeData::MeshMakeData(const NodeDefManager *ndef,
|
||||
u16 side_length, MeshGrid mesh_grid) :
|
||||
m_side_length(side_length),
|
||||
m_mesh_grid(mesh_grid),
|
||||
m_nodedef(ndef)
|
||||
{
|
||||
assert(m_side_length > 0);
|
||||
}
|
||||
|
||||
void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
|
||||
{
|
||||
|
@ -38,8 +42,9 @@ void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
|
|||
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
|
||||
|
||||
m_vmanip.clear();
|
||||
// extra 1 block thick layer around the mesh
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (crack_level >= 0)
|
||||
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
|
||||
*/
|
||||
|
@ -133,7 +151,7 @@ u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef)
|
|||
static u16 getSmoothLightCombined(const v3s16 &p,
|
||||
const std::array<v3s16,8> &dirs, MeshMakeData *data)
|
||||
{
|
||||
const NodeDefManager *ndef = data->nodedef;
|
||||
const NodeDefManager *ndef = data->m_nodedef;
|
||||
|
||||
u16 ambient_occlusion = 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)
|
||||
{
|
||||
const NodeDefManager *ndef = data->nodedef;
|
||||
const NodeDefManager *ndef = data->m_nodedef;
|
||||
const ContentFeatures &f = ndef->get(mn);
|
||||
tile = f.tiles[tileindex];
|
||||
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)
|
||||
{
|
||||
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),
|
||||
// (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):
|
||||
m_tsrc(client->getTextureSource()),
|
||||
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_last_crack(-1)
|
||||
{
|
||||
|
@ -602,10 +620,12 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
for (auto &m : m_mesh)
|
||||
m = make_irr<scene::SMesh>();
|
||||
|
||||
auto mesh_grid = client->getMeshGrid();
|
||||
auto mesh_grid = data->m_mesh_grid;
|
||||
v3s16 bp = data->m_blockpos;
|
||||
// Only generate minimap mapblocks at even coordinates.
|
||||
if (mesh_grid.isMeshPos(bp) && client->getMinimap()) {
|
||||
// Only generate minimap mapblocks at grid aligned coordinates.
|
||||
// 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);
|
||||
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);
|
||||
|
||||
MeshCollector collector(m_bounding_sphere_center, offset);
|
||||
/*
|
||||
Add special graphics:
|
||||
- torches
|
||||
- flowing water
|
||||
- fences
|
||||
- whatever
|
||||
*/
|
||||
|
||||
{
|
||||
// Generate everything
|
||||
MapblockMeshGenerator(data, &collector).generate();
|
||||
}
|
||||
|
||||
|
@ -640,9 +656,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
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);
|
||||
|
||||
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}];
|
||||
info.tile = p.layer;
|
||||
info.frame = 0;
|
||||
if (desync_animations) {
|
||||
// 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;
|
||||
}
|
||||
info.frame_offset = 0;
|
||||
// Replace tile texture with the first animation frame
|
||||
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.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(
|
||||
|
@ -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
|
||||
m_has_animation =
|
||||
|
@ -947,21 +961,22 @@ video::SColor encode_light(u16 light, u8 emissive_light)
|
|||
|
||||
u8 get_solid_sides(MeshMakeData *data)
|
||||
{
|
||||
std::unordered_map<v3s16, u8> results;
|
||||
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++)
|
||||
for (s16 j = 0; j < data->side_length && result != 0; j++) {
|
||||
u8 result = 0x3F; // all sides solid
|
||||
for (s16 i = 0; i < side && result != 0; i++)
|
||||
for (s16 j = 0; j < side && result != 0; j++) {
|
||||
v3s16 positions[6] = {
|
||||
v3s16(0, i, j),
|
||||
v3s16(data->side_length - 1, i, j),
|
||||
v3s16(side - 1, i, j),
|
||||
v3s16(i, 0, j),
|
||||
v3s16(i, data->side_length - 1, j),
|
||||
v3s16(i, side - 1, j),
|
||||
v3s16(i, j, 0),
|
||||
v3s16(i, j, data->side_length - 1)
|
||||
v3s16(i, j, side - 1)
|
||||
};
|
||||
|
||||
for (u8 k = 0; k < 6; k++) {
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "IMesh.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
#include "util/numeric.h"
|
||||
#include "client/tile.h"
|
||||
#include "voxel.h"
|
||||
|
@ -13,6 +16,10 @@
|
|||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace irr::video {
|
||||
class IVideoDriver;
|
||||
}
|
||||
|
||||
class Client;
|
||||
class NodeDefManager;
|
||||
class IShaderSource;
|
||||
|
@ -29,14 +36,25 @@ struct MinimapMapblock;
|
|||
struct MeshMakeData
|
||||
{
|
||||
VoxelManipulator m_vmanip;
|
||||
|
||||
// base pos of meshgen area, in blocks
|
||||
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);
|
||||
bool m_generate_minimap = 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)
|
||||
|
@ -44,15 +62,15 @@ struct MeshMakeData
|
|||
void fillBlockDataBegin(const v3s16 &blockpos);
|
||||
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
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "S3DVertex.h"
|
||||
#include "debug.h"
|
||||
#include "log.h"
|
||||
#include <cmath>
|
||||
|
@ -11,6 +10,9 @@
|
|||
#include <IAnimatedMesh.h>
|
||||
#include <SAnimatedMesh.h>
|
||||
#include <IAnimatedMeshSceneNode.h>
|
||||
#include "S3DVertex.h"
|
||||
#include "SMesh.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
inline static void applyShadeFactor(video::SColor& color, float factor)
|
||||
{
|
||||
|
|
|
@ -4,10 +4,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "SColor.h"
|
||||
#include "SMaterialLayer.h"
|
||||
#include "irrlichttypes_extrabloated.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
|
||||
* normal vector.
|
||||
|
|
|
@ -40,6 +40,7 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
|
|||
m_client(client)
|
||||
{
|
||||
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
|
||||
m_cache_enable_water_reflections = g_settings->getBool("enable_water_reflections");
|
||||
}
|
||||
|
||||
MeshUpdateQueue::~MeshUpdateQueue()
|
||||
|
@ -176,7 +177,8 @@ void MeshUpdateQueue::done(v3s16 pos)
|
|||
void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
|
||||
{
|
||||
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;
|
||||
|
||||
data->fillBlockDataBegin(q->p);
|
||||
|
@ -191,7 +193,9 @@ void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -69,8 +69,9 @@ private:
|
|||
std::unordered_set<v3s16> m_inflight_blocks;
|
||||
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_enable_water_reflections;
|
||||
|
||||
void fillDataFromMapBlocks(QueuedMeshUpdate *q);
|
||||
};
|
||||
|
|
|
@ -41,45 +41,6 @@ void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *verti
|
|||
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(
|
||||
const TileLayer &layer, u8 layernum, u32 numVertices)
|
||||
{
|
||||
|
|
|
@ -35,21 +35,12 @@ struct MeshCollector
|
|||
void append(const TileSpec &material,
|
||||
const video::S3DVertex *vertices, u32 numVertices,
|
||||
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:
|
||||
void append(const TileLayer &material,
|
||||
const video::S3DVertex *vertices, u32 numVertices,
|
||||
const u16 *indices, u32 numIndices,
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -4,18 +4,35 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../hud.h"
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "rect.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
#include "../hud.h"
|
||||
#include "mapnode.h"
|
||||
#include "util/thread.h"
|
||||
#include "voxel.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace irr {
|
||||
namespace video {
|
||||
class IVideoDriver;
|
||||
class IImage;
|
||||
class ITexture;
|
||||
}
|
||||
|
||||
namespace scene {
|
||||
class ISceneNode;
|
||||
}
|
||||
}
|
||||
|
||||
class Client;
|
||||
class NodeDefManager;
|
||||
class ITextureSource;
|
||||
class IShaderSource;
|
||||
class VoxelManipulator;
|
||||
|
||||
#define MINIMAP_MAX_SX 512
|
||||
#define MINIMAP_MAX_SY 512
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "settings.h"
|
||||
#include "profiler.h"
|
||||
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
using BlendMode = ParticleParamTypes::BlendMode;
|
||||
|
||||
ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc)
|
||||
|
|
|
@ -4,12 +4,21 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "ISceneNode.h"
|
||||
#include "S3DVertex.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "../particles.h"
|
||||
|
||||
namespace irr::video {
|
||||
class ITexture;
|
||||
}
|
||||
|
||||
struct ClientEvent;
|
||||
class ParticleManager;
|
||||
class ClientEnvironment;
|
||||
|
|
|
@ -18,7 +18,7 @@ void SetColorMaskStep::run(PipelineContext &context)
|
|||
{
|
||||
video::SOverrideMaterial &mat = context.device->getVideoDriver()->getOverrideMaterial();
|
||||
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.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID |
|
||||
scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT;
|
||||
|
|
|
@ -21,7 +21,7 @@ PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_t
|
|||
void PostProcessingStep::configureMaterial()
|
||||
{
|
||||
material.UseMipMaps = false;
|
||||
material.ZBuffer = true;
|
||||
material.ZBuffer = video::ECFN_LESSEQUAL;
|
||||
material.ZWriteEnable = video::EZW_ON;
|
||||
for (u32 k = 0; k < texture_map.size(); ++k) {
|
||||
material.TextureLayers[k].AnisotropicFilter = 0;
|
||||
|
@ -196,7 +196,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
|||
}
|
||||
|
||||
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");
|
||||
auto volume = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_DEPTH });
|
||||
|
|
|
@ -50,8 +50,7 @@ void FpsControl::limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused)
|
|||
|
||||
if (busy_time < frametime_min) {
|
||||
sleep_time = frametime_min - busy_time;
|
||||
if (sleep_time > 0)
|
||||
sleep_us(sleep_time);
|
||||
porting::preciseSleepUs(sleep_time);
|
||||
} else {
|
||||
sleep_time = 0;
|
||||
}
|
||||
|
|
|
@ -687,13 +687,23 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||
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_WAVING_LIQUID 1\n";
|
||||
break;
|
||||
default:
|
||||
shaders_header << "#define MATERIAL_WAVING_LIQUID 0\n";
|
||||
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_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
|
||||
|
|
|
@ -13,18 +13,6 @@
|
|||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
float radius = boundVec.getLength();
|
||||
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
|
||||
// but the future_frustum position must be the actual world position
|
||||
|
|
|
@ -27,7 +27,7 @@ static video::SMaterial baseMaterial()
|
|||
video::SMaterial mat;
|
||||
mat.ZBuffer = video::ECFN_DISABLED;
|
||||
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].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
|
||||
mat.BackfaceCulling = false;
|
||||
|
|
|
@ -50,6 +50,11 @@ struct FrameSpec
|
|||
video::ITexture *texture = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* We have two tile layers:
|
||||
* layer 0 = base
|
||||
* layer 1 = overlay
|
||||
*/
|
||||
#define MAX_TILE_LAYERS 2
|
||||
|
||||
//! Defines a layer of a tile.
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include <IMeshManipulator.h>
|
||||
#include "client/renderingengine.h"
|
||||
|
||||
#define WIELD_SCALE_FACTOR 30.0
|
||||
#define WIELD_SCALE_FACTOR_EXTRUDED 40.0
|
||||
#define WIELD_SCALE_FACTOR 30.0f
|
||||
#define WIELD_SCALE_FACTOR_EXTRUDED 40.0f
|
||||
|
||||
#define MIN_EXTRUSION_MESH_RESOLUTION 16
|
||||
#define MAX_EXTRUSION_MESH_RESOLUTION 512
|
||||
|
@ -225,18 +225,6 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
|
|||
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,
|
||||
const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc,
|
||||
u8 num_frames)
|
||||
|
@ -251,6 +239,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
|||
|
||||
core::dimension2d<u32> dim = texture->getSize();
|
||||
// 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) {
|
||||
u32 frame_height = dim.Height / num_frames;
|
||||
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,
|
||||
tsrc->getTexture(imagename));
|
||||
if (overlay_texture) {
|
||||
// duplicate the extruded mesh for the overlay
|
||||
scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0));
|
||||
copy->getMaterial().setTexture(0, overlay_texture);
|
||||
mesh->addMeshBuffer(copy);
|
||||
copy->drop();
|
||||
}
|
||||
mesh->recalculateBoundingBox();
|
||||
changeToMesh(mesh);
|
||||
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)
|
||||
{
|
||||
MeshMakeData mesh_make_data(client->ndef(), 1);
|
||||
MeshCollector collector(v3f(0.0f * BS), v3f());
|
||||
mesh_make_data.setSmoothLighting(false);
|
||||
MapblockMeshGenerator gen(&mesh_make_data, &collector);
|
||||
|
||||
n.setParam1(0xff);
|
||||
if (n.getParam2()) {
|
||||
// keep it
|
||||
} 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) {
|
||||
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();
|
||||
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) {
|
||||
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
|
||||
const FrameSpec &frame = (*p.layer.frames)[0];
|
||||
p.layer.texture = frame.texture;
|
||||
}
|
||||
for (video::S3DVertex &v : p.vertices) {
|
||||
for (video::S3DVertex &v : p.vertices)
|
||||
v.Color.setAlpha(255);
|
||||
}
|
||||
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
buf->Material.setTexture(0, p.layer.texture);
|
||||
p.layer.applyMaterialOptions(buf->Material);
|
||||
mesh->addMeshBuffer(buf);
|
||||
|
||||
auto buf = make_irr<scene::SMeshBuffer>();
|
||||
buf->append(&p.vertices[0], p.vertices.size(),
|
||||
&p.indices[0], p.indices.size());
|
||||
buf->drop();
|
||||
colors->push_back(
|
||||
ItemPartColor(p.layer.has_color, p.layer.color));
|
||||
|
||||
// Set up material
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -375,15 +376,12 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
|||
}
|
||||
|
||||
// Handle nodes
|
||||
// See also CItemDefManager::createClientCached()
|
||||
if (def.type == ITEM_NODE) {
|
||||
bool cull_backface = f.needsBackfaceCulling();
|
||||
|
||||
// Select rendering method
|
||||
switch (f.drawtype) {
|
||||
case NDT_AIRLIKE:
|
||||
setExtruded("no_texture_airlike.png", "",
|
||||
v3f(1.0, 1.0, 1.0), tsrc, 1);
|
||||
v3f(1), tsrc, 1);
|
||||
break;
|
||||
case NDT_SIGNLIKE:
|
||||
case NDT_TORCHLIKE:
|
||||
|
@ -393,38 +391,33 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
|||
v3f wscale = wield_scale;
|
||||
if (f.drawtype == NDT_FLOWINGLIQUID)
|
||||
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];
|
||||
m_colors.emplace_back(l0.has_color, l0.color);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case NDT_PLANTLIKE_ROOTED: {
|
||||
setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id),
|
||||
"", wield_scale, tsrc,
|
||||
f.special_tiles[0].layers[0].animation_frame_count);
|
||||
// Add color
|
||||
// use the plant tile
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case NDT_NORMAL:
|
||||
case NDT_ALLFACES:
|
||||
case NDT_LIQUID:
|
||||
setCube(f, wield_scale);
|
||||
break;
|
||||
default: {
|
||||
// Render non-trivial drawtypes like the actual node
|
||||
// Render all other drawtypes like the actual node
|
||||
MapNode n(id);
|
||||
if (def.place_param2)
|
||||
n.setParam2(*def.place_param2);
|
||||
|
||||
mesh = createSpecialNodeMesh(client, n, &m_colors, f);
|
||||
mesh = createGenericNodeMesh(client, n, &m_colors, f);
|
||||
changeToMesh(mesh);
|
||||
mesh->drop();
|
||||
m_meshnode->setScale(
|
||||
|
@ -437,9 +430,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
|||
u32 material_count = m_meshnode->getMaterialCount();
|
||||
for (u32 i = 0; i < material_count; ++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.MaterialTypeParam = 0.5f;
|
||||
material.BackfaceCulling = cull_backface;
|
||||
material.forEachTexture([this] (auto &tex) {
|
||||
setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter,
|
||||
m_anisotropic_filter);
|
||||
|
@ -550,8 +543,6 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
|
|||
// Shading is on by default
|
||||
result->needs_shading = true;
|
||||
|
||||
bool cull_backface = f.needsBackfaceCulling();
|
||||
|
||||
// If inventory_image is defined, it overrides everything else
|
||||
const std::string inventory_image = item.getInventoryImage(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;
|
||||
} else if (def.type == ITEM_NODE) {
|
||||
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: {
|
||||
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];
|
||||
result->buffer_colors.emplace_back(l0.has_color, l0.color);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case NDT_PLANTLIKE_ROOTED: {
|
||||
mesh = getExtrudedMesh(tsrc,
|
||||
tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), "");
|
||||
// Add color
|
||||
// Use the plant tile
|
||||
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);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Render non-trivial drawtypes like the actual node
|
||||
// Render all other drawtypes like the actual node
|
||||
MapNode n(id);
|
||||
if (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));
|
||||
break;
|
||||
}
|
||||
|
@ -621,13 +593,13 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
|
|||
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||
video::SMaterial &material = buf->getMaterial();
|
||||
// FIXME: overriding this breaks different alpha modes the mesh may have
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
material.forEachTexture([] (auto &tex) {
|
||||
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
|
||||
tex.MagFilter = video::ETMAGF_NEAREST;
|
||||
});
|
||||
material.BackfaceCulling = cull_backface;
|
||||
}
|
||||
|
||||
rotateMeshXZby(mesh, -45);
|
||||
|
@ -648,7 +620,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
|
|||
const std::string &imagename, const std::string &overlay_name)
|
||||
{
|
||||
// check textures
|
||||
video::ITexture *texture = tsrc->getTextureForMesh(imagename);
|
||||
video::ITexture *texture = tsrc->getTexture(imagename);
|
||||
if (!texture) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -683,56 +655,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
|
|||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
}
|
||||
scaleMesh(mesh, v3f(2.0, 2.0, 2.0));
|
||||
scaleMesh(mesh, v3f(2));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,6 @@ public:
|
|||
WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1);
|
||||
virtual ~WieldMeshSceneNode();
|
||||
|
||||
void setCube(const ContentFeatures &f, v3f wield_scale);
|
||||
void setExtruded(const std::string &imagename, const std::string &overlay_image,
|
||||
v3f wield_scale, ITextureSource *tsrc, u8 num_frames);
|
||||
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,
|
||||
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);
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
// Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
|
||||
#pragma once
|
||||
#include "config.h"
|
||||
#include "convert_json.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include <string>
|
||||
|
||||
enum class ContentType
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &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:
|
||||
// Add all the mods that come from modpacks
|
||||
// Second iteration:
|
||||
|
@ -56,9 +56,12 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
|
|||
std::set<std::string> seen_this_iteration;
|
||||
|
||||
for (const ModSpec &mod : new_mods) {
|
||||
if (mod.part_of_modpack != (bool)want_from_modpack)
|
||||
if (mod.part_of_modpack != want_from_modpack)
|
||||
continue;
|
||||
|
||||
// unrelated to this code, but we want to assert it somewhere
|
||||
assert(fs::IsPathAbsolute(mod.path));
|
||||
|
||||
if (existing_mods.count(mod.name) == 0) {
|
||||
// GOOD CASE: completely new mod.
|
||||
m_unsatisfied_mods.push_back(mod);
|
||||
|
|
|
@ -167,6 +167,7 @@ std::map<std::string, ModSpec> getModsInPath(
|
|||
|
||||
mod_path.clear();
|
||||
mod_path.append(path).append(DIR_DELIM).append(modname);
|
||||
mod_path = fs::AbsolutePath(mod_path);
|
||||
|
||||
mod_virtual_path.clear();
|
||||
// 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);
|
||||
parseModContents(spec);
|
||||
result.insert(std::make_pair(modname, spec));
|
||||
result[modname] = std::move(spec);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ struct ModSpec
|
|||
{
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string path;
|
||||
std::string path; // absolute path on disk
|
||||
std::string desc;
|
||||
int release = 0;
|
||||
|
||||
|
|
|
@ -22,9 +22,8 @@
|
|||
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";
|
||||
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);
|
||||
}
|
||||
|
||||
getGameMinetestConfig(gamespec.path, *game_settings);
|
||||
getGameConfig(gamespec.path, *game_settings);
|
||||
game_settings->removeSecureSettings();
|
||||
|
||||
infostream << "Initializing world at " << final_path << std::endl;
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
#include "gettime.h"
|
||||
#include "log.h"
|
||||
#include "log.h" // unused. for convenience.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FUNCTION_NAME __FUNCTION__
|
||||
|
|
|
@ -82,7 +82,6 @@ void set_default_settings()
|
|||
|
||||
// Client
|
||||
settings->setDefault("address", "");
|
||||
settings->setDefault("enable_sound", "true");
|
||||
#if defined(__unix__) && !defined(__APPLE__) && !defined (__ANDROID__)
|
||||
// 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
|
||||
|
@ -270,7 +269,6 @@ void set_default_settings()
|
|||
settings->setDefault("cinematic", "false");
|
||||
settings->setDefault("camera_smoothing", "0.0");
|
||||
settings->setDefault("cinematic_camera_smoothing", "0.7");
|
||||
settings->setDefault("enable_clouds", "true");
|
||||
settings->setDefault("view_bobbing_amount", "1.0");
|
||||
settings->setDefault("fall_bobbing_amount", "0.03");
|
||||
settings->setDefault("enable_3d_clouds", "true");
|
||||
|
@ -292,14 +290,11 @@ void set_default_settings()
|
|||
settings->setDefault("hud_scaling", "1.0");
|
||||
settings->setDefault("gui_scaling", "1.0");
|
||||
settings->setDefault("gui_scaling_filter", "false");
|
||||
settings->setDefault("gui_scaling_filter_txr2img", "true");
|
||||
settings->setDefault("smooth_scrolling", "true");
|
||||
settings->setDefault("desynchronize_mapblock_texture_animation", "false");
|
||||
settings->setDefault("hud_hotbar_max_width", "1.0");
|
||||
settings->setDefault("enable_local_map_saving", "false");
|
||||
settings->setDefault("show_entity_selectionbox", "false");
|
||||
settings->setDefault("ambient_occlusion_gamma", "1.8");
|
||||
settings->setDefault("enable_particles", "true");
|
||||
settings->setDefault("arm_inertia", "true");
|
||||
settings->setDefault("show_nametag_backgrounds", "true");
|
||||
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_filters", "1");
|
||||
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_sky_body_orbit_tilt", "0.0");
|
||||
settings->setDefault("enable_sun_tint", "false");
|
||||
|
@ -420,7 +415,6 @@ void set_default_settings()
|
|||
#endif
|
||||
|
||||
// Server
|
||||
settings->setDefault("disable_escape_sequences", "false");
|
||||
settings->setDefault("strip_color_codes", "false");
|
||||
#ifndef NDEBUG
|
||||
settings->setDefault("random_mod_load_order", "true");
|
||||
|
@ -440,7 +434,6 @@ void set_default_settings()
|
|||
settings->setDefault("protocol_version_min", "1");
|
||||
settings->setDefault("player_transfer_distance", "0");
|
||||
settings->setDefault("max_simultaneous_block_sends_per_client", "40");
|
||||
settings->setDefault("time_send_interval", "5");
|
||||
|
||||
settings->setDefault("motd", "");
|
||||
settings->setDefault("max_users", "15");
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <mutex>
|
||||
#include "network/networkprotocol.h"
|
||||
#include "irr_v3d.h"
|
||||
#include "util/container.h"
|
||||
#include "util/metricsbackend.h"
|
||||
#include "mapgen/mapgen.h" // for MapgenParams
|
||||
#include "map.h"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "gettext.h"
|
||||
#include "irrlicht_changes/CGUITTFont.h"
|
||||
#include "util/string.h"
|
||||
#include "guiScrollBar.h"
|
||||
#include <string>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
inline u32 getScrollbarSize(IGUIEnvironment* env)
|
||||
{
|
||||
return env->getSkin()->getSize(gui::EGDS_SCROLLBAR_SIZE);
|
||||
}
|
||||
|
||||
GUIChatConsole::GUIChatConsole(
|
||||
gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent,
|
||||
|
@ -62,15 +68,14 @@ GUIChatConsole::GUIChatConsole(
|
|||
}
|
||||
|
||||
const u16 chat_font_size = g_settings->getU16("chat_font_size");
|
||||
m_font = g_fontengine->getFont(chat_font_size != 0 ?
|
||||
rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono);
|
||||
m_font.grab(g_fontengine->getFont(chat_font_size != 0 ?
|
||||
rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono));
|
||||
|
||||
if (!m_font) {
|
||||
errorstream << "GUIChatConsole: Unable to load mono font" << std::endl;
|
||||
} else {
|
||||
core::dimension2d<u32> dim = m_font->getDimension(L"M");
|
||||
m_fontsize = v2u32(dim.Width, dim.Height);
|
||||
m_font->grab();
|
||||
}
|
||||
m_fontsize.X = MYMAX(m_fontsize.X, 1);
|
||||
m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
|
||||
|
@ -81,12 +86,11 @@ GUIChatConsole::GUIChatConsole(
|
|||
// track ctrl keys for mouse event
|
||||
m_is_ctrl_down = false;
|
||||
m_cache_clickable_chat_weblinks = g_settings->getBool("clickable_chat_weblinks");
|
||||
}
|
||||
|
||||
GUIChatConsole::~GUIChatConsole()
|
||||
{
|
||||
if (m_font)
|
||||
m_font->drop();
|
||||
m_scrollbar.reset(new GUIScrollBar(env, this, -1, core::rect<s32>(0, 0, 30, m_height), false, true, tsrc));
|
||||
m_scrollbar->setSubElement(true);
|
||||
m_scrollbar->setLargeStep(1);
|
||||
m_scrollbar->setSmallStep(1);
|
||||
}
|
||||
|
||||
void GUIChatConsole::openConsole(f32 scale)
|
||||
|
@ -121,6 +125,7 @@ void GUIChatConsole::closeConsole()
|
|||
m_open = false;
|
||||
Environment->removeFocus(this);
|
||||
m_menumgr->deletingMenu(this);
|
||||
m_scrollbar->setVisible(false);
|
||||
}
|
||||
|
||||
void GUIChatConsole::closeConsoleAtOnce()
|
||||
|
@ -180,6 +185,10 @@ void GUIChatConsole::draw()
|
|||
m_screensize = screensize;
|
||||
m_desired_height = m_desired_height_fraction * m_screensize.Y;
|
||||
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
|
||||
|
@ -204,6 +213,9 @@ void GUIChatConsole::reformatConsole()
|
|||
s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
|
||||
if (cols <= 0 || rows <= 0)
|
||||
cols = rows = 0;
|
||||
|
||||
updateScrollbar(true);
|
||||
|
||||
recalculateConsolePosition();
|
||||
m_chat_backend->reformat(cols, rows);
|
||||
}
|
||||
|
@ -293,10 +305,17 @@ void GUIChatConsole::drawBackground()
|
|||
|
||||
void GUIChatConsole::drawText()
|
||||
{
|
||||
if (m_font == NULL)
|
||||
if (!m_font)
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
const ChatFormattedLine& line = buf.getFormattedLine(row);
|
||||
|
@ -315,13 +334,13 @@ void GUIChatConsole::drawText()
|
|||
|
||||
if (m_font->getType() == irr::gui::EGFT_CUSTOM) {
|
||||
// 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(
|
||||
fragment.text,
|
||||
destrect,
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
||||
&rect);
|
||||
} else {
|
||||
// Otherwise use standard text
|
||||
m_font->draw(
|
||||
|
@ -330,10 +349,12 @@ void GUIChatConsole::drawText()
|
|||
video::SColor(255, 255, 255, 255),
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
||||
&rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateScrollbar();
|
||||
}
|
||||
|
||||
void GUIChatConsole::drawPrompt()
|
||||
|
@ -680,6 +701,11 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
prompt.input(std::wstring(event.StringInput.Str->c_str()));
|
||||
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;
|
||||
}
|
||||
|
@ -692,6 +718,7 @@ void GUIChatConsole::setVisible(bool visible)
|
|||
m_height = 0;
|
||||
recalculateConsolePosition();
|
||||
}
|
||||
m_scrollbar->setVisible(visible);
|
||||
}
|
||||
|
||||
bool GUIChatConsole::weblinkClick(s32 col, s32 row)
|
||||
|
@ -763,3 +790,18 @@ void GUIChatConsole::updatePrimarySelection()
|
|||
std::string selected = wide_to_utf8(wselected);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
#include "modalMenu.h"
|
||||
#include "chat.h"
|
||||
#include "config.h"
|
||||
#include "irr_ptr.h"
|
||||
|
||||
class Client;
|
||||
class GUIScrollBar;
|
||||
|
||||
class GUIChatConsole : public gui::IGUIElement
|
||||
{
|
||||
|
@ -20,7 +22,6 @@ public:
|
|||
ChatBackend* backend,
|
||||
Client* client,
|
||||
IMenuManager* menumgr);
|
||||
virtual ~GUIChatConsole();
|
||||
|
||||
// Open the console (height = desired fraction of screen size)
|
||||
// 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.
|
||||
void updatePrimarySelection();
|
||||
|
||||
void updateScrollbar(bool update_size = false);
|
||||
|
||||
private:
|
||||
ChatBackend* m_chat_backend;
|
||||
Client* m_client;
|
||||
IMenuManager* m_menumgr;
|
||||
irr_ptr<GUIScrollBar> m_scrollbar;
|
||||
|
||||
// current screen size
|
||||
v2u32 m_screensize;
|
||||
|
@ -116,7 +120,7 @@ private:
|
|||
video::SColor m_background_color = video::SColor(255, 0, 0, 0);
|
||||
|
||||
// font
|
||||
gui::IGUIFont *m_font = nullptr;
|
||||
irr_ptr<gui::IGUIFont> m_font;
|
||||
v2u32 m_fontsize;
|
||||
|
||||
// Enable clickable chat weblinks
|
||||
|
|
|
@ -130,7 +130,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
|||
|
||||
// create soundmanager
|
||||
#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(),
|
||||
std::make_unique<MenuMusicFetcher>());
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
#include <cassert>
|
||||
#include <list>
|
||||
|
||||
#include "IGUIEnvironment.h"
|
||||
|
||||
namespace irr::gui {
|
||||
class IGUIStaticText;
|
||||
}
|
||||
|
||||
class IGameCallback
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "IGUIElement.h"
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "irr_ptr.h"
|
||||
|
||||
#include "util/string.h"
|
||||
#ifdef __ANDROID__
|
||||
#include <porting_android.h>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
class ISimpleTextureSource;
|
||||
namespace irr::gui
|
||||
{
|
||||
class IGUIButton;
|
||||
class IGUIImage;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{}
|
|
@ -29,7 +29,14 @@ struct AutoExposure
|
|||
/// @brief Power value for center-weighted metering. Value of 1.0 measures entire screen uniformly
|
||||
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)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
17
src/map.cpp
|
@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map):
|
|||
assert(map);
|
||||
}
|
||||
|
||||
void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
|
||||
bool load_if_inexistent)
|
||||
void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent)
|
||||
{
|
||||
TimeTaker timer1("initialEmerge", &emerge_time);
|
||||
|
||||
assert(m_map);
|
||||
|
||||
// Units of these are MapBlocks
|
||||
v3s16 p_min = blockpos_min;
|
||||
v3s16 p_max = blockpos_max;
|
||||
|
||||
VoxelArea block_area_nodes
|
||||
(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;
|
||||
}
|
||||
|
||||
const bool all_new = m_area.hasEmptyExtent() || block_area_nodes.contains(m_area);
|
||||
addArea(block_area_nodes);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/*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_is_dirty = false;
|
||||
if (all_new)
|
||||
m_is_dirty = false;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
assert(!m_loaded_blocks.empty());
|
||||
for (auto &loaded_block : m_loaded_blocks) {
|
||||
v3s16 p = loaded_block.first;
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
|
|
|
@ -298,9 +298,6 @@ protected:
|
|||
u32 needed_count);
|
||||
};
|
||||
|
||||
#define VMANIP_BLOCK_DATA_INEXIST 1
|
||||
#define VMANIP_BLOCK_CONTAINS_CIGNORE 2
|
||||
|
||||
class MMVManip : public VoxelManipulator
|
||||
{
|
||||
public:
|
||||
|
@ -344,4 +341,8 @@ protected:
|
|||
value = flags describing the block
|
||||
*/
|
||||
std::map<v3s16, u8> m_loaded_blocks;
|
||||
|
||||
enum : u8 {
|
||||
VMANIP_BLOCK_DATA_INEXIST = 1 << 0,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -73,6 +73,12 @@ MapBlock::~MapBlock()
|
|||
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()
|
||||
{
|
||||
// Ignore if no stored objects (to not set changed flag)
|
||||
|
@ -84,7 +90,7 @@ bool MapBlock::onObjectsActivation()
|
|||
<< "activating " << count << " objects in block " << getPos()
|
||||
<< 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: "
|
||||
<< count << " in " << getPos() << "; removing all of them."
|
||||
<< std::endl;
|
||||
|
@ -99,7 +105,7 @@ bool MapBlock::onObjectsActivation()
|
|||
|
||||
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
|
||||
<< " statically but block " << getPos() << " already contains "
|
||||
<< m_static_objects.getStoredSize() << " objects."
|
||||
|
|