diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index 46977b147..c4cf2b84b 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -38,6 +38,7 @@ varying vec3 vPosition; // precision must be considered). varying vec3 worldPosition; varying lowp vec4 varColor; +varying lowp vec3 hwColor; #ifdef GL_ES varying mediump vec2 varTexCoord; #else @@ -375,7 +376,7 @@ void main(void) #endif color = base.rgb; - vec4 col = vec4(color.rgb * varColor.rgb, 1.0); + vec4 col = vec4(color * hwColor * varColor.rgb, 1.0); #ifdef ENABLE_DYNAMIC_SHADOWS if (f_shadow_strength > 0.0) { diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl index d96164d76..89cdec90d 100644 --- a/client/shaders/nodes_shader/opengl_vertex.glsl +++ b/client/shaders/nodes_shader/opengl_vertex.glsl @@ -6,6 +6,8 @@ uniform vec3 dayLight; uniform highp vec3 cameraOffset; uniform float animationTimer; +uniform vec3 ambientLight; + varying vec3 vNormal; varying vec3 vPosition; // World position in the visible world (i.e. relative to the cameraOffset.) @@ -15,6 +17,7 @@ varying vec3 vPosition; // precision must be considered). varying vec3 worldPosition; varying lowp vec4 varColor; +varying lowp vec3 hwColor; // The centroid keyword ensures that after interpolation the texture coordinates // lie within the same bounds when MSAA is en- and disabled. // This fixes the stripes problem with nearest-neighbor textures and MSAA. @@ -220,8 +223,12 @@ void main(void) color.b += max(0.0, 0.021 - abs(0.2 * brightness - 0.021) + 0.07 * brightness); + color.rgb += ambientLight; + varColor = clamp(color, 0.0, 1.0); + hwColor = inVertexTangent.xyz; + #ifdef ENABLE_DYNAMIC_SHADOWS if (f_shadow_strength > 0.0) { #if MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl index d5a434da5..e1930aad0 100644 --- a/client/shaders/object_shader/opengl_vertex.glsl +++ b/client/shaders/object_shader/opengl_vertex.glsl @@ -2,6 +2,7 @@ uniform mat4 mWorld; uniform vec3 dayLight; uniform float animationTimer; uniform lowp vec4 emissiveColor; +uniform vec3 ambientLight; varying vec3 vNormal; varying vec3 vPosition; @@ -129,6 +130,8 @@ void main(void) color.b += max(0.0, 0.021 - abs(0.2 * brightness - 0.021) + 0.07 * brightness); + color.rgb += ambientLight; + varColor = clamp(color, 0.0, 1.0); diff --git a/doc/lua_api.md b/doc/lua_api.md index ee1f4060b..3482af4bf 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8409,6 +8409,14 @@ child will follow movement and rotation of that bone. * `set_lighting(light_definition)`: sets lighting for the player * Passing no arguments resets lighting to its default values. * `light_definition` is a table with the following optional fields: + * `ambient_light` is a ColorSpec controlling color of global ambient light; + (default: `{a = 255, r = 0, g = 0, b = 0}` / last set value). + * It works only if shaders are enabled. + * Alpha is ignored (it is always set to 255). + * Note: Total light is clamped before being applied. + This means that when an object is fully lit, ambient light + will take no effect. Setting ambient light to `"#FFFFFF"` + will make all objects be fully lit at all times ("fullbright"). * `saturation` sets the saturation (vividness; default: `1.0`). * values > 1 increase the saturation * values in [0,1] decrease the saturation diff --git a/games/devtest/mods/lighting/init.lua b/games/devtest/mods/lighting/init.lua index 7b4392fb8..182c05c4b 100644 --- a/games/devtest/mods/lighting/init.lua +++ b/games/devtest/mods/lighting/init.lua @@ -14,6 +14,14 @@ local lighting_sections = { {n = "speed_bright_dark", d = "Dark scene adaptation speed", min = -10, max = 10, type="log2"}, {n = "center_weight_power", d = "Power factor for center-weighting", min = 0.1, max = 10}, } + }, + { + n = "ambient_light", d = "Ambient Light", + entries = { + {n = "r", d = "Red", min = 0, max = 255}, + {n = "g", d = "Green", min = 0, max = 255}, + {n = "b", d = "Blue", min = 0, max = 255} + } } } @@ -61,7 +69,7 @@ minetest.register_chatcommand("set_lighting", { local form = { "formspec_version[2]", - "size[15,30]", + "size[15,32]", "position[0.99,0.15]", "anchor[1,0]", "padding[0.05,0.1]", @@ -137,4 +145,4 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) player:hud_change(hud_id, "text", debug_value) player:set_lighting(lighting) -end) \ No newline at end of file +end) diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index d451d0911..cf211ce48 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -57,6 +57,7 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/inputhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp ${CMAKE_CURRENT_SOURCE_DIR}/keycode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/light_colors.cpp ${CMAKE_CURRENT_SOURCE_DIR}/localplayer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mapblock_mesh.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mesh.cpp diff --git a/src/client/camera.cpp b/src/client/camera.cpp index 5e724d05e..3551b6e8c 100644 --- a/src/client/camera.cpp +++ b/src/client/camera.cpp @@ -139,7 +139,7 @@ void Camera::step(f32 dtime) if (m_wield_change_timer >= 0 && was_under_zero) { m_wieldnode->setItem(m_wield_item_next, m_client); - m_wieldnode->setNodeLightColor(m_player_light_color); + m_wieldnode->setColor(m_player_light_color); } if (m_view_bobbing_state != 0) @@ -552,7 +552,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio) m_wieldnode->setRotation(wield_rotation); m_player_light_color = player->light_color; - m_wieldnode->setNodeLightColor(m_player_light_color); + m_wieldnode->setColor(m_player_light_color); // Set render distance updateViewingRange(); diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index 7e1676ffe..925cb187c 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "porting.h" #include #include "client/renderingengine.h" +#include "light_colors.h" /* ClientEnvironment @@ -262,7 +263,11 @@ void ClientEnvironment::step(float dtime) u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef()); lplayer->light_color = encode_light(light, 0); // this transfers light.alpha - final_color_blend(&lplayer->light_color, light, day_night_ratio); + + video::SColor ambient_light = g_settings->getBool("enable_shaders") ? + lplayer->getLighting().ambient_light : video::SColor(255, 0, 0, 0); + + final_color_blend(&lplayer->light_color, light, day_night_ratio, ambient_light); } /* diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 0044cc16e..c39d11ab0 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -48,6 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/shader.h" #include "client/minimap.h" #include +#include "light_colors.h" class Settings; struct ToolCapabilities; @@ -921,7 +922,7 @@ void GenericCAO::setNodeLight(const video::SColor &light_color) { if (m_prop.visual == "wielditem" || m_prop.visual == "item") { if (m_wield_meshnode) - m_wield_meshnode->setNodeLightColor(light_color); + m_wield_meshnode->setColor(light_color); return; } diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index c351c4b80..9132f0410 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/renderingengine.h" #include "client.h" #include "noise.h" +#include "light_colors.h" // Distance of light extrapolation (for oversized nodes) // After this distance, it gives up and considers light level constant diff --git a/src/client/game.cpp b/src/client/game.cpp index 88892beb5..e6811943c 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -79,6 +79,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "hud.h" #include "clientdynamicinfo.h" #include +#include "light_colors.h" #if USE_SOUND #include "client/sound/sound_openal.h" @@ -382,6 +383,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter CachedPixelShaderSetting m_animation_timer_delta_pixel{"animationTimerDelta"}; CachedPixelShaderSetting m_day_light{"dayLight"}; + CachedVertexShaderSetting m_ambient_light{"ambientLight"}; CachedPixelShaderSetting m_minimap_yaw{"yawVec"}; CachedPixelShaderSetting m_camera_offset_pixel{"cameraOffset"}; CachedVertexShaderSetting m_camera_offset_vertex{"cameraOffset"}; @@ -473,6 +475,11 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter get_sunlight_color(&sunlight, daynight_ratio); m_day_light.set(sunlight, services); + Lighting &lighting = m_client->getEnv().getLocalPlayer()->getLighting(); + + video::SColorf ambient_light_f(lighting.ambient_light); + m_ambient_light.set(ambient_light_f, services); + u32 animation_timer = m_client->getEnv().getFrameTime() % 1000000; float animation_timer_f = (float)animation_timer / 100000.f; m_animation_timer_vertex.set(&animation_timer_f, services); @@ -504,7 +511,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter m_texel_size0_vertex.set(m_texel_size0, services); m_texel_size0_pixel.set(m_texel_size0, services); - const AutoExposure &exposure_params = m_client->getEnv().getLocalPlayer()->getLighting().exposure; + const AutoExposure &exposure_params = lighting.exposure; std::array exposure_buffer = { std::pow(2.0f, exposure_params.luminance_min), std::pow(2.0f, exposure_params.luminance_max), @@ -522,7 +529,6 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter m_bloom_strength_pixel.set(&m_bloom_strength, services); } - const auto &lighting = m_client->getEnv().getLocalPlayer()->getLighting(); float saturation = lighting.saturation; m_saturation_pixel.set(&saturation, services); @@ -1446,7 +1452,7 @@ void Game::copyServerClientCache() { // It would be possible to let the client directly read the media files // from where the server knows they are. But aside from being more complicated - // it would also *not* fill the media cache and cause slower joining of + // it would also *not* fill the media cache and cause slower joining of // remote servers. // (Imagine that you launch a game once locally and then connect to a server.) diff --git a/src/client/hud.cpp b/src/client/hud.cpp index c5e71b853..f837eb330 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -1139,9 +1139,9 @@ void drawItemStack( if (p.needColorize(c)) { buf->setDirty(scene::EBT_VERTEX); if (imesh->needs_shading) - colorizeMeshBuffer(buf, &c); + colorizeMeshBufferTangents(buf, &c); else - setMeshBufferColor(buf, c); + setMeshBufferTangentsColor(buf, c); } video::SMaterial &material = buf->getMaterial(); diff --git a/src/client/light_colors.cpp b/src/client/light_colors.cpp new file mode 100644 index 000000000..d47ed9e66 --- /dev/null +++ b/src/client/light_colors.cpp @@ -0,0 +1,99 @@ +/* +Minetest +Copyright (C) 2024 Andrey2470T, AndreyT + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "light_colors.h" + +video::SColor encode_light(u16 light, u8 emissive_light) +{ + // Get components + u32 day = (light & 0xff); + u32 night = (light >> 8); + // Add emissive light + night += emissive_light * 2.5f; + if (night > 255) + night = 255; + // Since we don't know if the day light is sunlight or + // artificial light, assume it is artificial when the night + // light bank is also lit. + if (day < night) + day = 0; + else + day = day - night; + u32 sum = day + night; + // Ratio of sunlight: + u32 r; + if (sum > 0) + r = day * 255 / sum; + else + r = 0; + // Average light: + float b = (day + night) / 2; + return video::SColor(r, b, b, b); +} + +void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio) +{ + f32 rg = daynight_ratio / 1000.0f - 0.04f; + f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f; + sunlight->r = rg; + sunlight->g = rg; + sunlight->b = b; +} + +void final_color_blend(video::SColor *result, + u16 light, u32 daynight_ratio, const video::SColorf &ambientLight) +{ + video::SColorf dayLight; + get_sunlight_color(&dayLight, daynight_ratio); + final_color_blend(result, + encode_light(light, 0), dayLight, ambientLight); +} + +void final_color_blend(video::SColor *result, + const video::SColor &data, const video::SColorf &dayLight, + const video::SColorf &ambientLight) +{ + static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f); + + video::SColorf c(data); + f32 n = 1 - c.a; + + f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f; + f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f; + f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f; + + // Emphase blue a bit in darker places + // Each entry of this array represents a range of 8 blue levels + static const u8 emphase_blue_when_dark[32] = { + 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255), + 0, 255) / 8] / 255.0f; + + // Add ambient light + r += ambientLight.r; + g += ambientLight.g; + b += ambientLight.b; + + result->setRed(core::clamp((s32)(r * 255.f), 0, 255)); + result->setGreen(core::clamp((s32)(g * 255.f), 0, 255)); + result->setBlue(core::clamp((s32)(b * 255.f), 0, 255)); +} diff --git a/src/client/light_colors.h b/src/client/light_colors.h new file mode 100644 index 000000000..bcf48ec20 --- /dev/null +++ b/src/client/light_colors.h @@ -0,0 +1,61 @@ +/* +Minetest +Copyright (C) 2024 Andrey2470T, AndreyT + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "irrlichttypes_extrabloated.h" + +/*! + * Encodes light of a node. + * The result is not the final color, but a + * half-baked vertex color. + * You have to multiply the resulting color + * with the node's color. + * + * \param light the first 8 bits are day light, + * the last 8 bits are night light + * \param emissive_light amount of light the surface emits, + * from 0 to LIGHT_SUN. + */ +video::SColor encode_light(u16 light, u8 emissive_light); + +/*! + * Returns the sunlight's color from the current + * day-night ratio. + */ +void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio); + +/*! + * Gives the final SColor shown on screen. + * + * \param result output color + * \param light first 8 bits are day light, second 8 bits are + * night light + */ +void final_color_blend(video::SColor *result, + u16 light, u32 daynight_ratio, const video::SColorf &ambientLight=video::SColorf(0.0f, 0.0f, 0.0f, 1.0f)); + +/*! + * Gives the final SColor shown on screen. + * + * \param result output color + * \param data the half-baked vertex color + * \param dayLight color of the sunlight + */ +void final_color_blend(video::SColor *result, + const video::SColor &data, const video::SColorf &dayLight, + const video::SColorf &ambientLight=video::SColorf(0.0f, 0.0f, 0.0f, 1.0f)); diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 429464e04..18d33dd15 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include "client/texturesource.h" +#include "light_colors.h" /* MeshMakeData @@ -281,49 +282,6 @@ u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData return getSmoothLightCombined(p, dirs, data); } -void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){ - f32 rg = daynight_ratio / 1000.0f - 0.04f; - f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f; - sunlight->r = rg; - sunlight->g = rg; - sunlight->b = b; -} - -void final_color_blend(video::SColor *result, - u16 light, u32 daynight_ratio) -{ - video::SColorf dayLight; - get_sunlight_color(&dayLight, daynight_ratio); - final_color_blend(result, - encode_light(light, 0), dayLight); -} - -void final_color_blend(video::SColor *result, - const video::SColor &data, const video::SColorf &dayLight) -{ - static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f); - - video::SColorf c(data); - f32 n = 1 - c.a; - - f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f; - f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f; - f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f; - - // Emphase blue a bit in darker places - // Each entry of this array represents a range of 8 blue levels - static const u8 emphase_blue_when_dark[32] = { - 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255), - 0, 255) / 8] / 255.0f; - - result->setRed(core::clamp((s32) (r * 255.0f), 0, 255)); - result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255)); - result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255)); -} /* Mesh generation helpers @@ -672,7 +630,8 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs { PreMeshBuffer &p = collector.prebuffers[layer][i]; - applyTileColor(p); + if (!m_enable_shaders) + applyTileColor(p); // Generate animation data // - Cracks @@ -759,10 +718,25 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs p.layer.applyMaterialOptions(material); } - scene::SMeshBuffer *buf = new scene::SMeshBuffer(); + scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents(); buf->Material = material; + + std::vector tangents; + + // Copy S3DVertex to S3DVertexTangents + for (auto &v : p.vertices) { + video::SColor &c = p.layer.color; + v3f hw_color{0.0f}; + + if (m_enable_shaders) { + hw_color.X = c.getRed() / 255.0f; + hw_color.Y = c.getGreen() / 255.0f; + hw_color.Z = c.getBlue() / 255.0f; + } + tangents.emplace_back(v.Pos, v.Normal, v.Color, v.TCoords, hw_color); + } if (p.layer.isTransparent()) { - buf->append(&p.vertices[0], p.vertices.size(), nullptr, 0); + buf->append(&tangents[0], tangents.size(), nullptr, 0); MeshTriangle t; t.buffer = buf; @@ -775,7 +749,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs m_transparent_triangles.push_back(t); } } else { - buf->append(&p.vertices[0], p.vertices.size(), + buf->append(&tangents[0], tangents.size(), &p.indices[0], p.indices.size()); } mesh->addMeshBuffer(buf); @@ -813,7 +787,7 @@ MapBlockMesh::~MapBlockMesh() } bool MapBlockMesh::animate(bool faraway, float time, int crack, - u32 daynight_ratio) + u32 daynight_ratio) { if (!m_has_animation) { m_animation_force_timer = 100000; @@ -876,20 +850,19 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) { video::SColorf day_color; get_sunlight_color(&day_color, daynight_ratio); - for (auto &daynight_diff : m_daynight_diffs) { auto *mesh = m_mesh[daynight_diff.first.first]; mesh->setDirty(scene::EBT_VERTEX); // force reload to VBO scene::IMeshBuffer *buf = mesh-> getMeshBuffer(daynight_diff.first.second); - video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices(); + video::S3DVertexTangents *vertices = static_cast(buf->getVertices()); + for (const auto &j : daynight_diff.second) final_color_blend(&(vertices[j.first].Color), j.second, - day_color); + day_color); } m_last_daynight_ratio = daynight_ratio; } - return true; } @@ -908,7 +881,7 @@ void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos) // arrange index sequences into partial buffers m_transparent_buffers.clear(); - scene::SMeshBuffer *current_buffer = nullptr; + scene::SMeshBufferTangents *current_buffer = nullptr; std::vector current_strain; for (auto i : triangle_refs) { const auto &t = m_transparent_triangles[i]; @@ -932,7 +905,7 @@ void MapBlockMesh::consolidateTransparentBuffers() { m_transparent_buffers.clear(); - scene::SMeshBuffer *current_buffer = nullptr; + scene::SMeshBufferTangents *current_buffer = nullptr; std::vector current_strain; // use the fact that m_transparent_triangles is already arranged by buffer @@ -954,34 +927,6 @@ void MapBlockMesh::consolidateTransparentBuffers() } } -video::SColor encode_light(u16 light, u8 emissive_light) -{ - // Get components - u32 day = (light & 0xff); - u32 night = (light >> 8); - // Add emissive light - night += emissive_light * 2.5f; - if (night > 255) - night = 255; - // Since we don't know if the day light is sunlight or - // artificial light, assume it is artificial when the night - // light bank is also lit. - if (day < night) - day = 0; - else - day = day - night; - u32 sum = day + night; - // Ratio of sunlight: - u32 r; - if (sum > 0) - r = day * 255 / sum; - else - r = 0; - // Average light: - float b = (day + night) / 2; - return video::SColor(r, b, b, b); -} - u8 get_solid_sides(MeshMakeData *data) { std::unordered_map results; diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index 7cd368762..ccab91461 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -74,7 +74,7 @@ struct MeshMakeData class MeshTriangle { public: - scene::SMeshBuffer *buffer; + scene::SMeshBufferTangents *buffer; u16 p1, p2, p3; v3f centroid; float areaSQ; @@ -152,7 +152,7 @@ class MapBlockBspTree class PartialMeshBuffer { public: - PartialMeshBuffer(scene::SMeshBuffer *buffer, std::vector &&vertex_indexes) : + PartialMeshBuffer(scene::SMeshBufferTangents *buffer, std::vector &&vertex_indexes) : m_buffer(buffer), m_vertex_indexes(std::move(vertex_indexes)) {} @@ -162,7 +162,7 @@ class PartialMeshBuffer void beforeDraw() const; void afterDraw() const; private: - scene::SMeshBuffer *m_buffer; + scene::SMeshBufferTangents *m_buffer; mutable std::vector m_vertex_indexes; }; @@ -284,52 +284,12 @@ class MapBlockMesh std::vector m_transparent_buffers; }; -/*! - * Encodes light of a node. - * The result is not the final color, but a - * half-baked vertex color. - * You have to multiply the resulting color - * with the node's color. - * - * \param light the first 8 bits are day light, - * the last 8 bits are night light - * \param emissive_light amount of light the surface emits, - * from 0 to LIGHT_SUN. - */ -video::SColor encode_light(u16 light, u8 emissive_light); - // Compute light at node u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef); u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef); u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data); u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data); -/*! - * Returns the sunlight's color from the current - * day-night ratio. - */ -void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio); - -/*! - * Gives the final SColor shown on screen. - * - * \param result output color - * \param light first 8 bits are day light, second 8 bits are - * night light - */ -void final_color_blend(video::SColor *result, - u16 light, u32 daynight_ratio); - -/*! - * Gives the final SColor shown on screen. - * - * \param result output color - * \param data the half-baked vertex color - * \param dayLight color of the sunlight - */ -void final_color_blend(video::SColor *result, - const video::SColor &data, const video::SColorf &dayLight); - // Retrieves the TileSpec of a face of a node // Adds MATERIAL_FLAG_CRACK if the node is cracked // TileSpec should be passed as reference due to the underlying TileFrame and its vector diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 711f7e1c6..b0a028b78 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include inline static void applyShadeFactor(video::SColor& color, float factor) { @@ -53,50 +54,55 @@ void applyFacesShading(video::SColor &color, const v3f &normal) applyShadeFactor(color, 0.670820f * x2 + 1.000000f * y2 + 0.836660f * z2); } +template +std::array getCubeVertices(video::SColor c) +{ + return std::array{ + // Up + T(-0.5,+0.5,-0.5, 0,1,0, c, 0,1), + T(-0.5,+0.5,+0.5, 0,1,0, c, 0,0), + T(+0.5,+0.5,+0.5, 0,1,0, c, 1,0), + T(+0.5,+0.5,-0.5, 0,1,0, c, 1,1), + // Down + T(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0), + T(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0), + T(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1), + T(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1), + // Right + T(+0.5,-0.5,-0.5, 1,0,0, c, 0,1), + T(+0.5,+0.5,-0.5, 1,0,0, c, 0,0), + T(+0.5,+0.5,+0.5, 1,0,0, c, 1,0), + T(+0.5,-0.5,+0.5, 1,0,0, c, 1,1), + // Left + T(-0.5,-0.5,-0.5, -1,0,0, c, 1,1), + T(-0.5,-0.5,+0.5, -1,0,0, c, 0,1), + T(-0.5,+0.5,+0.5, -1,0,0, c, 0,0), + T(-0.5,+0.5,-0.5, -1,0,0, c, 1,0), + // Back + T(-0.5,-0.5,+0.5, 0,0,1, c, 1,1), + T(+0.5,-0.5,+0.5, 0,0,1, c, 0,1), + T(+0.5,+0.5,+0.5, 0,0,1, c, 0,0), + T(-0.5,+0.5,+0.5, 0,0,1, c, 1,0), + // Front + T(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1), + T(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0), + T(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0), + T(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1), + }; +} + scene::IAnimatedMesh* createCubeMesh(v3f scale) { video::SColor c(255,255,255,255); - video::S3DVertex vertices[24] = - { - // Up - video::S3DVertex(-0.5,+0.5,-0.5, 0,1,0, c, 0,1), - video::S3DVertex(-0.5,+0.5,+0.5, 0,1,0, c, 0,0), - video::S3DVertex(+0.5,+0.5,+0.5, 0,1,0, c, 1,0), - video::S3DVertex(+0.5,+0.5,-0.5, 0,1,0, c, 1,1), - // Down - video::S3DVertex(-0.5,-0.5,-0.5, 0,-1,0, c, 0,0), - video::S3DVertex(+0.5,-0.5,-0.5, 0,-1,0, c, 1,0), - video::S3DVertex(+0.5,-0.5,+0.5, 0,-1,0, c, 1,1), - video::S3DVertex(-0.5,-0.5,+0.5, 0,-1,0, c, 0,1), - // Right - video::S3DVertex(+0.5,-0.5,-0.5, 1,0,0, c, 0,1), - video::S3DVertex(+0.5,+0.5,-0.5, 1,0,0, c, 0,0), - video::S3DVertex(+0.5,+0.5,+0.5, 1,0,0, c, 1,0), - video::S3DVertex(+0.5,-0.5,+0.5, 1,0,0, c, 1,1), - // Left - video::S3DVertex(-0.5,-0.5,-0.5, -1,0,0, c, 1,1), - video::S3DVertex(-0.5,-0.5,+0.5, -1,0,0, c, 0,1), - video::S3DVertex(-0.5,+0.5,+0.5, -1,0,0, c, 0,0), - video::S3DVertex(-0.5,+0.5,-0.5, -1,0,0, c, 1,0), - // Back - video::S3DVertex(-0.5,-0.5,+0.5, 0,0,1, c, 1,1), - video::S3DVertex(+0.5,-0.5,+0.5, 0,0,1, c, 0,1), - video::S3DVertex(+0.5,+0.5,+0.5, 0,0,1, c, 0,0), - video::S3DVertex(-0.5,+0.5,+0.5, 0,0,1, c, 1,0), - // Front - video::S3DVertex(-0.5,-0.5,-0.5, 0,0,-1, c, 0,1), - video::S3DVertex(-0.5,+0.5,-0.5, 0,0,-1, c, 0,0), - video::S3DVertex(+0.5,+0.5,-0.5, 0,0,-1, c, 1,0), - video::S3DVertex(+0.5,-0.5,-0.5, 0,0,-1, c, 1,1), - }; + std::array vertices = getCubeVertices(c); u16 indices[6] = {0,1,2,2,3,0}; scene::SMesh *mesh = new scene::SMesh(); for (u32 i=0; i<6; ++i) { scene::IMeshBuffer *buf = new scene::SMeshBuffer(); - buf->append(vertices + 4 * i, 4, indices, 6); + buf->append(&vertices[0] + 4 * i, 4, indices, 6); // Set default material buf->getMaterial().Lighting = false; buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; @@ -115,9 +121,39 @@ scene::IAnimatedMesh* createCubeMesh(v3f scale) return anim_mesh; } +scene::IAnimatedMesh* createCubeMeshTangents(v3f scale) +{ + video::SColor c(255,255,255,255); + + std::array vertices = getCubeVertices(c); + u16 indices[6] = {0,1,2,2,3,0}; + + scene::SMesh *mesh = new scene::SMesh(); + for (u32 i=0; i<6; ++i) + { + scene::IMeshBuffer *buf = new scene::SMeshBufferTangents(); + buf->append(&vertices[0] + 4 * i, 4, indices, 6); + // Set default material + buf->getMaterial().Lighting = false; + buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + buf->getMaterial().forEachTexture([] (auto &tex) { + tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; + tex.MagFilter = video::ETMAGF_NEAREST; + }); + // Add mesh buffer to mesh + mesh->addMeshBuffer(buf); + buf->drop(); + } + + scene::SAnimatedMesh *anim_mesh = new scene::SAnimatedMesh(mesh); + mesh->drop(); + scaleMeshTangents(anim_mesh, scale); // also recalculates bounding box + return anim_mesh; +} + void scaleMesh(scene::IMesh *mesh, v3f scale) { - if (mesh == NULL) + if (!mesh) return; aabb3f bbox; @@ -126,11 +162,9 @@ void scaleMesh(scene::IMesh *mesh, v3f scale) u32 mc = mesh->getMeshBufferCount(); for (u32 j = 0; j < mc; j++) { scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); - const u32 stride = getVertexPitchFromType(buf->getVertexType()); - u32 vertex_count = buf->getVertexCount(); - u8 *vertices = (u8 *)buf->getVertices(); - for (u32 i = 0; i < vertex_count; i++) - ((video::S3DVertex *)(vertices + i * stride))->Pos *= scale; + video::S3DVertex *vertices = static_cast(buf->getVertices()); + for (u32 i = 0; i < buf->getVertexCount(); i++) + vertices[i].Pos *= scale; buf->recalculateBoundingBox(); @@ -143,9 +177,9 @@ void scaleMesh(scene::IMesh *mesh, v3f scale) mesh->setBoundingBox(bbox); } -void translateMesh(scene::IMesh *mesh, v3f vec) +void scaleMeshTangents(scene::IMesh *mesh, v3f scale) { - if (mesh == NULL) + if (!mesh) return; aabb3f bbox; @@ -154,11 +188,35 @@ void translateMesh(scene::IMesh *mesh, v3f vec) u32 mc = mesh->getMeshBufferCount(); for (u32 j = 0; j < mc; j++) { scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); - const u32 stride = getVertexPitchFromType(buf->getVertexType()); - u32 vertex_count = buf->getVertexCount(); - u8 *vertices = (u8 *)buf->getVertices(); - for (u32 i = 0; i < vertex_count; i++) - ((video::S3DVertex *)(vertices + i * stride))->Pos += vec; + video::S3DVertexTangents *vertices = static_cast(buf->getVertices()); + for (u32 i = 0; i < buf->getVertexCount(); i++) + vertices[i].Pos *= scale; + + buf->recalculateBoundingBox(); + + // calculate total bounding box + if (j == 0) + bbox = buf->getBoundingBox(); + else + bbox.addInternalBox(buf->getBoundingBox()); + } + mesh->setBoundingBox(bbox); +} + +void translateMeshTangents(scene::IMesh *mesh, v3f vec) +{ + if (!mesh) + return; + + aabb3f bbox; + bbox.reset(0, 0, 0); + + u32 mc = mesh->getMeshBufferCount(); + for (u32 j = 0; j < mc; j++) { + scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); + video::S3DVertexTangents *vertices = static_cast(buf->getVertices()); + for (u32 i = 0; i < buf->getVertexCount(); i++) + vertices[i].Pos += vec; buf->recalculateBoundingBox(); @@ -173,11 +231,20 @@ void translateMesh(scene::IMesh *mesh, v3f vec) void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color) { - const u32 stride = getVertexPitchFromType(buf->getVertexType()); - u32 vertex_count = buf->getVertexCount(); - u8 *vertices = (u8 *) buf->getVertices(); - for (u32 i = 0; i < vertex_count; i++) - ((video::S3DVertex *) (vertices + i * stride))->Color = color; + video::S3DVertex *vertices = static_cast(buf->getVertices()); + for (u32 i = 0; i < buf->getVertexCount(); i++) + vertices[i].Color = color; +} + +void setMeshBufferTangentsColor(scene::IMeshBuffer *buf, + const video::SColor &color, const video::SColor &hw_color) +{ + video::S3DVertexTangents *vertices = static_cast(buf->getVertices()); + + for (u32 i = 0; i < buf->getVertexCount(); i++) { + vertices[i].Color = color; + vertices[i].Tangent = v3f(hw_color.getRed(), hw_color.getGreen(), hw_color.getBlue()); + } } void setAnimatedMeshColor(scene::IAnimatedMeshSceneNode *node, const video::SColor &color) @@ -189,44 +256,37 @@ void setAnimatedMeshColor(scene::IAnimatedMeshSceneNode *node, const video::SCol void setMeshColor(scene::IMesh *mesh, const video::SColor &color) { - if (mesh == NULL) + if (!mesh) return; - u32 mc = mesh->getMeshBufferCount(); - for (u32 j = 0; j < mc; j++) + for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) setMeshBufferColor(mesh->getMeshBuffer(j), color); } void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u32 count) { - const u32 stride = getVertexPitchFromType(buf->getVertexType()); assert(buf->getVertexCount() >= count); - u8 *vertices = (u8 *) buf->getVertices(); + video::S3DVertex *vertices = static_cast(buf->getVertices()); for (u32 i = 0; i < count; i++) - ((video::S3DVertex*) (vertices + i * stride))->TCoords = uv[i]; + vertices[i].TCoords = uv[i]; } -template +template static void applyToMesh(scene::IMesh *mesh, const F &fn) { - u16 mc = mesh->getMeshBufferCount(); - for (u16 j = 0; j < mc; j++) { + for (u16 j = 0; j < mesh->getMeshBufferCount(); j++) { scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); - const u32 stride = getVertexPitchFromType(buf->getVertexType()); - u32 vertex_count = buf->getVertexCount(); - char *vertices = reinterpret_cast(buf->getVertices()); - for (u32 i = 0; i < vertex_count; i++) - fn(reinterpret_cast(vertices + i * stride)); + T *vertices = static_cast(buf->getVertices()); + for (u32 i = 0; i < buf->getVertexCount(); i++) + fn(&vertices[i]); } } -void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolor) +void colorizeMeshBufferTangents(scene::IMeshBuffer *buf, const video::SColor *buffercolor) { - const u32 stride = getVertexPitchFromType(buf->getVertexType()); - u32 vertex_count = buf->getVertexCount(); - u8 *vertices = (u8 *) buf->getVertices(); - for (u32 i = 0; i < vertex_count; i++) { - video::S3DVertex *vertex = (video::S3DVertex *) (vertices + i * stride); + video::S3DVertexTangents *vertices = static_cast(buf->getVertices()); + for (u32 i = 0; i < buf->getVertexCount(); i++) { + video::S3DVertexTangents *vertex = &vertices[i]; video::SColor *vc = &(vertex->Color); // Reset color *vc = *buffercolor; @@ -235,27 +295,6 @@ void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolo } } -void setMeshColorByNormalXYZ(scene::IMesh *mesh, - const video::SColor &colorX, - const video::SColor &colorY, - const video::SColor &colorZ) -{ - if (!mesh) - return; - auto colorizator = [=] (video::S3DVertex *vertex) { - f32 x = fabs(vertex->Normal.X); - f32 y = fabs(vertex->Normal.Y); - f32 z = fabs(vertex->Normal.Z); - if (x >= y && x >= z) - vertex->Color = colorX; - else if (y >= z) - vertex->Color = colorY; - else - vertex->Color = colorZ; - }; - applyToMesh(mesh, colorizator); -} - void setMeshColorByNormal(scene::IMesh *mesh, const v3f &normal, const video::SColor &color) { @@ -265,37 +304,47 @@ void setMeshColorByNormal(scene::IMesh *mesh, const v3f &normal, if (vertex->Normal == normal) vertex->Color = color; }; - applyToMesh(mesh, colorizator); + applyToMesh(mesh, colorizator); } -template +template static void rotateMesh(scene::IMesh *mesh, float degrees) { degrees *= M_PI / 180.0f; float c = std::cos(degrees); float s = std::sin(degrees); - auto rotator = [c, s] (video::S3DVertex *vertex) { + auto rotator = [c, s] (T *vertex) { float u = vertex->Pos.*U; float v = vertex->Pos.*V; vertex->Pos.*U = c * u - s * v; vertex->Pos.*V = s * u + c * v; }; - applyToMesh(mesh, rotator); + applyToMesh(mesh, rotator); } void rotateMeshXYby(scene::IMesh *mesh, f64 degrees) { - rotateMesh<&v3f::X, &v3f::Y>(mesh, degrees); + rotateMesh(mesh, degrees); } void rotateMeshXZby(scene::IMesh *mesh, f64 degrees) { - rotateMesh<&v3f::X, &v3f::Z>(mesh, degrees); + rotateMesh(mesh, degrees); +} + +void rotateMeshTangentsXZby(scene::IMesh *mesh, f64 degrees) +{ + rotateMesh(mesh, degrees); } void rotateMeshYZby(scene::IMesh *mesh, f64 degrees) { - rotateMesh<&v3f::Y, &v3f::Z>(mesh, degrees); + rotateMesh(mesh, degrees); +} + +void rotateMeshTangentsYZby(scene::IMesh *mesh, f64 degrees) +{ + rotateMesh(mesh, degrees); } void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir) @@ -357,7 +406,7 @@ scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer) { switch (mesh_buffer->getVertexType()) { case video::EVT_STANDARD: { - video::S3DVertex *v = (video::S3DVertex *) mesh_buffer->getVertices(); + video::S3DVertex *v = static_cast(mesh_buffer->getVertices()); u16 *indices = mesh_buffer->getIndices(); scene::SMeshBuffer *cloned_buffer = new scene::SMeshBuffer(); cloned_buffer->append(v, mesh_buffer->getVertexCount(), indices, @@ -366,7 +415,7 @@ scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer) } case video::EVT_2TCOORDS: { video::S3DVertex2TCoords *v = - (video::S3DVertex2TCoords *) mesh_buffer->getVertices(); + static_cast(mesh_buffer->getVertices()); u16 *indices = mesh_buffer->getIndices(); scene::SMeshBufferLightMap *cloned_buffer = new scene::SMeshBufferLightMap(); @@ -376,7 +425,7 @@ scene::IMeshBuffer* cloneMeshBuffer(scene::IMeshBuffer *mesh_buffer) } case video::EVT_TANGENTS: { video::S3DVertexTangents *v = - (video::S3DVertexTangents *) mesh_buffer->getVertices(); + static_cast(mesh_buffer->getVertices()); u16 *indices = mesh_buffer->getIndices(); scene::SMeshBufferTangents *cloned_buffer = new scene::SMeshBufferTangents(); diff --git a/src/client/mesh.h b/src/client/mesh.h index 0c3e8942e..e8306e41d 100644 --- a/src/client/mesh.h +++ b/src/client/mesh.h @@ -38,27 +38,33 @@ void applyFacesShading(video::SColor &color, const v3f &normal); */ scene::IAnimatedMesh* createCubeMesh(v3f scale); +scene::IAnimatedMesh* createCubeMeshTangents(v3f scale); + /* Multiplies each vertex coordinate by the specified scaling factors (componentwise vector multiplication). */ void scaleMesh(scene::IMesh *mesh, v3f scale); +void scaleMeshTangents(scene::IMesh *mesh, v3f scale); /* Translate each vertex coordinate by the specified vector. */ -void translateMesh(scene::IMesh *mesh, v3f vec); +void translateMeshTangents(scene::IMesh *mesh, v3f vec); /*! * Sets a constant color for all vertices in the mesh buffer. */ void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color); +void setMeshBufferTangentsColor(scene::IMeshBuffer *buf, + const video::SColor &color, const video::SColor &hw_color=video::SColor(0xFFFFFFFF)); /* Set a constant color for all vertices in the mesh */ void setMeshColor(scene::IMesh *mesh, const video::SColor &color); - +void setMeshTangentsColor(scene::IMesh *mesh, const video::SColor &color, + const video::SColor &hw_color=video::SColor(0xFFFFFFFF)); /* Sets texture coords for vertices in the mesh buffer. @@ -75,18 +81,7 @@ void setAnimatedMeshColor(scene::IAnimatedMeshSceneNode *node, const video::SCol * Overwrites the color of a mesh buffer. * The color is darkened based on the normal vector of the vertices. */ -void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolor); - -/* - Set the color of all vertices in the mesh. - For each vertex, determine the largest absolute entry in - the normal vector, and choose one of colorX, colorY or - colorZ accordingly. -*/ -void setMeshColorByNormalXYZ(scene::IMesh *mesh, - const video::SColor &colorX, - const video::SColor &colorY, - const video::SColor &colorZ); +void colorizeMeshBufferTangents(scene::IMeshBuffer *buf, const video::SColor *buffercolor); void setMeshColorByNormal(scene::IMesh *mesh, const v3f &normal, const video::SColor &color); @@ -102,7 +97,9 @@ void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir); */ void rotateMeshXYby (scene::IMesh *mesh, f64 degrees); void rotateMeshXZby (scene::IMesh *mesh, f64 degrees); +void rotateMeshTangentsXZby(scene::IMesh *mesh, f64 degrees); void rotateMeshYZby (scene::IMesh *mesh, f64 degrees); +void rotateMeshTangentsYZby(scene::IMesh *mesh, f64 degrees); /* * Clone the mesh buffer. @@ -139,5 +136,5 @@ bool checkMeshNormals(scene::IMesh *mesh); Set the MinFilter, MagFilter and AnisotropicFilter properties of a texture layer according to the three relevant boolean values found in the Minetest settings. -*/ +*/ void setMaterialFilters(video::SMaterialLayer &tex, bool bilinear, bool trilinear, bool anisotropic); diff --git a/src/client/particles.cpp b/src/client/particles.cpp index c19282424..cb93b99cb 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -35,6 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client.h" #include "settings.h" #include "profiler.h" +#include "client/mapblock_mesh.h" +#include "light_colors.h" ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc) { @@ -185,11 +187,18 @@ video::SColor Particle::updateLight(ClientEnvironment *env) else light = blend_light(env->getDayNightRatio(), LIGHT_SUN, 0); - u8 m_light = decode_light(light + m_p.glow); + light = decode_light(light + m_p.glow); + + video::SColor light_color(0xFFFFFFFF); + video::SColor ambient_light = g_settings->getBool("enable_shaders") ? + env->getLocalPlayer()->getLighting().ambient_light : video::SColor(255, 0, 0, 0); + + final_color_blend(&light_color, static_cast(light) * 255, env->getDayNightRatio(), + ambient_light); return video::SColor(255, - m_light * m_base_color.getRed() / 255, - m_light * m_base_color.getGreen() / 255, - m_light * m_base_color.getBlue() / 255); + light_color.getRed() * m_base_color.getRed() / 255, + light_color.getGreen() * m_base_color.getGreen() / 255, + light_color.getBlue() * m_base_color.getBlue() / 255); } void Particle::updateVertices(ClientEnvironment *env, video::SColor color) diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 66f89efb1..182862dfd 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -45,23 +45,22 @@ static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y) { const f32 r = 0.5; - scene::IMeshBuffer *buf = new scene::SMeshBuffer(); + scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents(); video::SColor c(255,255,255,255); v3f scale(1.0, 1.0, 0.1); - // Front and back { - video::S3DVertex vertices[8] = { + video::S3DVertexTangents vertices[8] = { // z- - video::S3DVertex(-r,+r,-r, 0,0,-1, c, 0,0), - video::S3DVertex(+r,+r,-r, 0,0,-1, c, 1,0), - video::S3DVertex(+r,-r,-r, 0,0,-1, c, 1,1), - video::S3DVertex(-r,-r,-r, 0,0,-1, c, 0,1), + video::S3DVertexTangents(-r,+r,-r, 0,0,-1, c, 0,0), + video::S3DVertexTangents(+r,+r,-r, 0,0,-1, c, 1,0), + video::S3DVertexTangents(+r,-r,-r, 0,0,-1, c, 1,1), + video::S3DVertexTangents(-r,-r,-r, 0,0,-1, c, 0,1), // z+ - video::S3DVertex(-r,+r,+r, 0,0,+1, c, 0,0), - video::S3DVertex(-r,-r,+r, 0,0,+1, c, 0,1), - video::S3DVertex(+r,-r,+r, 0,0,+1, c, 1,1), - video::S3DVertex(+r,+r,+r, 0,0,+1, c, 1,0), + video::S3DVertexTangents(-r,+r,+r, 0,0,+1, c, 0,0), + video::S3DVertexTangents(-r,-r,+r, 0,0,+1, c, 0,1), + video::S3DVertexTangents(+r,-r,+r, 0,0,+1, c, 1,1), + video::S3DVertexTangents(+r,+r,+r, 0,0,+1, c, 1,0), }; u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4}; buf->append(vertices, 8, indices, 12); @@ -76,17 +75,17 @@ static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y) f32 x1 = pixelpos_x + pixelsize_x; f32 tex0 = (i + 0.1) * pixelsize_x; f32 tex1 = (i + 0.9) * pixelsize_x; - video::S3DVertex vertices[8] = { + video::S3DVertexTangents vertices[8] = { // x- - video::S3DVertex(x0,-r,-r, -1,0,0, c, tex0,1), - video::S3DVertex(x0,-r,+r, -1,0,0, c, tex1,1), - video::S3DVertex(x0,+r,+r, -1,0,0, c, tex1,0), - video::S3DVertex(x0,+r,-r, -1,0,0, c, tex0,0), + video::S3DVertexTangents(x0,-r,-r, -1,0,0, c, tex0,1), + video::S3DVertexTangents(x0,-r,+r, -1,0,0, c, tex1,1), + video::S3DVertexTangents(x0,+r,+r, -1,0,0, c, tex1,0), + video::S3DVertexTangents(x0,+r,-r, -1,0,0, c, tex0,0), // x+ - video::S3DVertex(x1,-r,-r, +1,0,0, c, tex0,1), - video::S3DVertex(x1,+r,-r, +1,0,0, c, tex0,0), - video::S3DVertex(x1,+r,+r, +1,0,0, c, tex1,0), - video::S3DVertex(x1,-r,+r, +1,0,0, c, tex1,1), + video::S3DVertexTangents(x1,-r,-r, +1,0,0, c, tex0,1), + video::S3DVertexTangents(x1,+r,-r, +1,0,0, c, tex0,0), + video::S3DVertexTangents(x1,+r,+r, +1,0,0, c, tex1,0), + video::S3DVertexTangents(x1,-r,+r, +1,0,0, c, tex1,1), }; u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4}; buf->append(vertices, 8, indices, 12); @@ -97,17 +96,17 @@ static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y) f32 y1 = -pixelpos_y; f32 tex0 = (i + 0.1) * pixelsize_y; f32 tex1 = (i + 0.9) * pixelsize_y; - video::S3DVertex vertices[8] = { + video::S3DVertexTangents vertices[8] = { // y- - video::S3DVertex(-r,y0,-r, 0,-1,0, c, 0,tex0), - video::S3DVertex(+r,y0,-r, 0,-1,0, c, 1,tex0), - video::S3DVertex(+r,y0,+r, 0,-1,0, c, 1,tex1), - video::S3DVertex(-r,y0,+r, 0,-1,0, c, 0,tex1), + video::S3DVertexTangents(-r,y0,-r, 0,-1,0, c, 0,tex0), + video::S3DVertexTangents(+r,y0,-r, 0,-1,0, c, 1,tex0), + video::S3DVertexTangents(+r,y0,+r, 0,-1,0, c, 1,tex1), + video::S3DVertexTangents(-r,y0,+r, 0,-1,0, c, 0,tex1), // y+ - video::S3DVertex(-r,y1,-r, 0,+1,0, c, 0,tex0), - video::S3DVertex(-r,y1,+r, 0,+1,0, c, 0,tex1), - video::S3DVertex(+r,y1,+r, 0,+1,0, c, 1,tex1), - video::S3DVertex(+r,y1,-r, 0,+1,0, c, 1,tex0), + video::S3DVertexTangents(-r,y1,-r, 0,+1,0, c, 0,tex0), + video::S3DVertexTangents(-r,y1,+r, 0,+1,0, c, 0,tex1), + video::S3DVertexTangents(+r,y1,+r, 0,+1,0, c, 1,tex1), + video::S3DVertexTangents(+r,y1,-r, 0,+1,0, c, 1,tex0), }; u16 indices[12] = {0,1,2,2,3,0,4,5,6,6,7,4}; buf->append(vertices, 8, indices, 12); @@ -117,7 +116,7 @@ static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y) scene::SMesh *mesh = new scene::SMesh(); mesh->addMeshBuffer(buf); buf->drop(); - scaleMesh(mesh, scale); // also recalculates bounding box + scaleMeshTangents(mesh, scale); // also recalculates bounding box return mesh; } @@ -144,7 +143,7 @@ class ExtrusionMeshCache: public IReferenceCounted m_extrusion_meshes[resolution] = createExtrusionMesh(resolution, resolution); } - m_cube = createCubeMesh(v3f(1.0, 1.0, 1.0)); + m_cube = createCubeMeshTangents(v3f(1.0, 1.0, 1.0)); } // Destructor virtual ~ExtrusionMeshCache() @@ -345,14 +344,16 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, p.layer.texture = frame.texture; p.layer.normal_texture = frame.normal_texture; } + std::vector tangents; for (video::S3DVertex &v : p.vertices) { v.Color.setAlpha(255); + tangents.emplace_back(v); } - scene::SMeshBuffer *buf = new scene::SMeshBuffer(); + scene::SMeshBufferTangents *buf = new scene::SMeshBufferTangents(); buf->Material.setTexture(0, p.layer.texture); p.layer.applyMaterialOptions(buf->Material); mesh->addMeshBuffer(buf); - buf->append(&p.vertices[0], p.vertices.size(), + buf->append(&tangents[0], tangents.size(), &p.indices[0], p.indices.size()); buf->drop(); colors->push_back( @@ -374,7 +375,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che scene::SMesh *mesh = nullptr; if (m_enable_shaders) { - u32 shader_id = shdrsrc->getShader("object_shader", TILE_MATERIAL_BASIC, NDT_NORMAL); + u32 shader_id = shdrsrc->getShader("nodes_shader", TILE_MATERIAL_BASIC, NDT_NORMAL); m_material_type = shdrsrc->getShaderInfo(shader_id).material; } @@ -500,33 +501,37 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che void WieldMeshSceneNode::setColor(video::SColor c) { + if (!m_meshnode) + return; + assert(!m_lighting); scene::IMesh *mesh = m_meshnode->getMesh(); if (!mesh) return; - u8 red = c.getRed(); - u8 green = c.getGreen(); - u8 blue = c.getBlue(); - const u32 mc = mesh->getMeshBufferCount(); if (mc > m_colors.size()) m_colors.resize(mc); for (u32 j = 0; j < mc; j++) { video::SColor bc(m_base_color); m_colors[j].applyOverride(bc); - video::SColor buffercolor(255, - bc.getRed() * red / 255, - bc.getGreen() * green / 255, - bc.getBlue() * blue / 255); + scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); + video::SColor buffercolor(255, + bc.getRed() * c.getRed() / 255, + bc.getGreen() * c.getGreen() / 255, + bc.getBlue() * c.getBlue() / 255); + if (m_colors[j].needColorize(buffercolor)) { buf->setDirty(scene::EBT_VERTEX); - if (m_enable_shaders) - setMeshBufferColor(buf, buffercolor); + if (m_enable_shaders) { + setMeshBufferTangentsColor(buf, + video::SColor(255, c.getRed(), c.getGreen(), c.getBlue()), + video::SColor(255, bc.getRed() / 255, bc.getGreen() / 255, bc.getBlue() / 255)); + } else - colorizeMeshBuffer(buf, &buffercolor); + colorizeMeshBufferTangents(buf, &buffercolor); } } } @@ -619,15 +624,15 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) 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)); + scaleMeshTangents(mesh, v3f(1.2, 0.03, 1.2)); + translateMeshTangents(mesh, v3f(0, -0.57, 0)); } else - scaleMesh(mesh, v3f(1.2, 1.2, 1.2)); + scaleMeshTangents(mesh, v3f(1.2, 1.2, 1.2)); // add overlays postProcessNodeMesh(mesh, f, false, false, nullptr, &result->buffer_colors, true); if (f.drawtype == NDT_ALLFACES) - scaleMesh(mesh, v3f(f.visual_scale)); + scaleMeshTangents(mesh, v3f(f.visual_scale)); break; } case NDT_PLANTLIKE: { @@ -656,7 +661,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) n.setParam2(*def.place_param2); mesh = createSpecialNodeMesh(client, n, &result->buffer_colors, f); - scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); + scaleMeshTangents(mesh, v3f(0.12, 0.12, 0.12)); break; } } @@ -674,8 +679,8 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) material.Lighting = false; } - rotateMeshXZby(mesh, -45); - rotateMeshYZby(mesh, -30); + rotateMeshTangentsXZby(mesh, -45); + rotateMeshTangentsYZby(mesh, -30); } // might need to be re-colorized, this is done only when needed @@ -728,7 +733,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)); + scaleMeshTangents(mesh, v3f(2.0, 2.0, 2.0)); return mesh; } diff --git a/src/lighting.h b/src/lighting.h index 262a48b5d..621adabf9 100644 --- a/src/lighting.h +++ b/src/lighting.h @@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #pragma once +#include "irrlichttypes_bloated.h" /** @@ -46,11 +47,11 @@ struct AutoExposure AutoExposure(); }; -/** Describes ambient light settings for a player - */ struct Lighting { AutoExposure exposure; + /// @brief Ambient light color & intensity for nodes & entities. Alpha is ignored. + video::SColor ambient_light {255, 0, 0, 0}; float shadow_intensity {0.0f}; float saturation {1.0f}; float volumetric_light_strength {0.0f}; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 90f2bed5b..5f2a4d8ee 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1801,18 +1801,28 @@ void Client::handleCommand_SetLighting(NetworkPacket *pkt) { Lighting& lighting = m_env.getLocalPlayer()->getLighting(); - if (pkt->getRemainingBytes() >= 4) - *pkt >> lighting.shadow_intensity; - if (pkt->getRemainingBytes() >= 4) - *pkt >> lighting.saturation; - if (pkt->getRemainingBytes() >= 24) { - *pkt >> lighting.exposure.luminance_min - >> lighting.exposure.luminance_max - >> lighting.exposure.exposure_correction - >> lighting.exposure.speed_dark_bright - >> lighting.exposure.speed_bright_dark - >> lighting.exposure.center_weight_power; - } - if (pkt->getRemainingBytes() >= 4) - *pkt >> lighting.volumetric_light_strength; + if (pkt->getRemainingBytes() < 4) + return; + *pkt >> lighting.shadow_intensity; + + if (pkt->getRemainingBytes() < 4) + return; + *pkt >> lighting.saturation; + + if (pkt->getRemainingBytes() < 24) + return; + *pkt >> lighting.exposure.luminance_min + >> lighting.exposure.luminance_max + >> lighting.exposure.exposure_correction + >> lighting.exposure.speed_dark_bright + >> lighting.exposure.speed_bright_dark + >> lighting.exposure.center_weight_power; + + if (pkt->getRemainingBytes() < 4) + return; + *pkt >> lighting.volumetric_light_strength; + + if (pkt->getRemainingBytes() < 4) + return; + *pkt >> lighting.ambient_light; } diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index bc5ddba5c..06b044f48 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2534,6 +2534,13 @@ int ObjectRef::l_set_lighting(lua_State *L) } lua_pop(L, 1); // shadows + lua_getfield(L, 2, "ambient_light"); + if (!lua_isnil(L, -1)) { + read_color(L, -1, &lighting.ambient_light); + lighting.ambient_light.setAlpha(255); // alpha should always be 255 + } + lua_pop(L, 1); // ambient light + getfloatfield(L, -1, "saturation", lighting.saturation); lua_getfield(L, 2, "exposure"); @@ -2553,7 +2560,7 @@ int ObjectRef::l_set_lighting(lua_State *L) lighting.volumetric_light_strength = rangelim(lighting.volumetric_light_strength, 0.0f, 1.0f); } lua_pop(L, 1); // volumetric_light -} + } getServer(L)->setLighting(player, lighting); return 0; @@ -2575,6 +2582,16 @@ int ObjectRef::l_get_lighting(lua_State *L) lua_pushnumber(L, lighting.shadow_intensity); lua_setfield(L, -2, "intensity"); lua_setfield(L, -2, "shadows"); + lua_newtable(L); // "ambient_light" + lua_pushnumber(L, lighting.ambient_light.getRed()); + lua_setfield(L, -2, "r"); + lua_pushnumber(L, lighting.ambient_light.getGreen()); + lua_setfield(L, -2, "g"); + lua_pushnumber(L, lighting.ambient_light.getBlue()); + lua_setfield(L, -2, "b"); + lua_pushnumber(L, 255); + lua_setfield(L, -2, "a"); + lua_setfield(L, -2, "ambient_light"); lua_pushnumber(L, lighting.saturation); lua_setfield(L, -2, "saturation"); lua_newtable(L); // "exposure" diff --git a/src/server.cpp b/src/server.cpp index 937cbe90a..36c5f2670 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1891,6 +1891,8 @@ void Server::SendSetLighting(session_t peer_id, const Lighting &lighting) pkt << lighting.volumetric_light_strength; + pkt << lighting.ambient_light; + Send(&pkt); }