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

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

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

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

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

View file

@ -14,6 +14,9 @@ https://www.apache.org/licenses/LICENSE-2.0.html
Textures by Zughy are under CC BY-SA 4.0
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

View file

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

View file

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

View file

@ -56,6 +56,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
dofile(menupath .. DIR_DELIM .. "dlg_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"),

View file

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

View file

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

View file

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

View file

@ -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
@ -5062,6 +5062,8 @@ Methods
* `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!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

After

Width:  |  Height:  |  Size: 134 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 134 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 144 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 132 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 B

After

Width:  |  Height:  |  Size: 121 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 115 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

After

Width:  |  Height:  |  Size: 124 B

Before After
Before After

View file

@ -12,6 +12,7 @@ unittests.list = {}
-- player = false, -- Does test require a player?
-- 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -164,13 +164,6 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters &params
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();

View file

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

View file

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

View file

@ -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();

View file

@ -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();

View file

@ -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");

View file

@ -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");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -91,7 +91,6 @@ 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();
#endif

View file

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

View file

@ -656,13 +656,11 @@ 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),
@ -671,10 +669,20 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
};
if (m_is_player) {
// Move minimal Y position to 0 (feet position)
for (video::S3DVertex &vertex : vertices)
for (auto &vertex : vertices)
vertex.Pos.Y += dy;
}
u16 indices[] = {0,1,2,2,3,0};
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);
}
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));

View file

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

View file

@ -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),
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)));
(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,30 +1692,36 @@ 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();
if (data->m_smooth_lighting) {
// Mesh is always private here. So the lighting is applied to each
// vertex right here.
if (data->m_smooth_lighting) {
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();
}

View file

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

View file

@ -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");
}
} 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");
}
} 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");
}
#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;
} 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,7 +3005,6 @@ void Game::updateCamera(f32 dtime)
client->updateCameraOffset(camera_offset);
client->getEnv().updateCameraOffset(camera_offset);
if (clouds)
clouds->updateCameraOffset(camera_offset);
}
}
@ -3683,11 +3664,9 @@ 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);
}
}
if (!runData.digging) {
infostream << "Started digging" << std::endl;
@ -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);
}
// Send event to trigger sound
client->getEventManager()->put(new NodeDugEvent(nodepos, n));
@ -3866,7 +3842,6 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
/*
Update clouds
*/
if (clouds)
updateClouds(dtime);
/*
@ -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);

View file

@ -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") << "]";
}
#endif
#endif
if (g_touchcontrols) {
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;"
<< strgettext("Touchscreen Layout") << "]";

View file

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

View file

@ -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();

View file

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

View file

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

View file

@ -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;
}
// 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++) {

View file

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

View file

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

View file

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

View file

@ -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;
}
/*

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map):
assert(map);
}
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,15 +808,11 @@ 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;
}
if (all_new)
m_is_dirty = false;
}
@ -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);

View file

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

View file

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

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