Compare commits

...

18 Commits

Author SHA1 Message Date
Andrey
7f588a2963
Merge b08ee987a6b06d9baedf09ad7c1198c65f935689 into 9a1501ae89ffe79c38dbd6756c9e7ed647dd7dc1 2024-06-28 00:36:55 +03:00
grorp
9a1501ae89
CIrrDeviceSDL: Fix numpad key events not having correct KeyInput.Char (#14780)
Allows you to change viewing range using numpad +/- again. This fix also works with the current unreleased version of SDL 3.

The keycodes for numpad keys (both SDL keycodes and Irrlicht keycodes) are not the same as the keycodes for the equivalent non-numpad keys and don't correspond to chars, so I mapped them to chars manually.

Since I think the resolution of https://github.com/minetest/minetest/issues/13770 was "just disable numlock", I made sure to only do this for the numpad number keys if numlock is enabled.
2024-06-27 14:44:44 +02:00
Erich Schubert
514e106414
Fix missing newline before Markdown list (#14783)
Renders incorrectly e.g. on https://api.minetest.net/spatial-vectors/
2024-06-26 22:21:18 +02:00
Andrey2470T
b08ee987a6 Replaced C-style cast of void* vertices to static_cast, reverted adding emissive color to GenericCAO 2024-06-09 13:26:32 +03:00
Andrey2470T
d3b63ba06f Use S3DVertexTangents for mapblocks & wield meshes for separate saving light and hardware colors 2024-06-06 01:05:51 +03:00
Andrey2470T
385bb3c801 Fixed the ambient light for particles, some code improvements 2024-05-24 23:33:54 +03:00
Lars Mueller
56392c2d08 Clarify that light is clamped before being applied 2024-05-24 23:33:54 +03:00
Lars Mueller
80418e0069 Scale particle light properly 2024-05-24 23:33:54 +03:00
Andrey2470T
698a63cc5c Fixed the particles light calculation 2024-05-24 23:33:54 +03:00
Andrey2470T
1aa03addec Moved ambient light applying to the vertex shaders, tiny code cleanups 2024-05-24 23:33:54 +03:00
Andrey2470T
4a351df32b Added ambient light to devtest, setting alpha always to 255 and some other improvements 2024-05-24 23:33:54 +03:00
Andrey2470T
41ab0eb0fd Support ambient light only for the shaders 2024-05-24 23:33:54 +03:00
Lars Mueller
8a7676d2f6 Ambient light improvements 2024-05-24 23:33:54 +03:00
Andrey2470T
811f5bacde Some fixes and improvements 2024-05-24 23:33:54 +03:00
Andrey2470T
220ece672c Add ambient light to light color, calculate the color in final_color_blend() if shaders are off 2024-05-24 23:33:54 +03:00
Andrey2470T
ff7ba2b7a1 Don't whiten mapblocks and entities if the ambient light color is grayscale 2024-05-24 23:33:53 +03:00
Andrey2470T
17a75185e1 Update loaded mapblocks meshes if luminance was set, added doc 2024-05-24 23:33:53 +03:00
Andrey2470T
02d0c826fe Ambient light and server control for that 2024-05-24 23:33:53 +03:00
26 changed files with 582 additions and 340 deletions

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

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

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

@ -3902,6 +3902,7 @@ Operators
---------
Operators can be used if all of the involved vectors have metatables:
* `v1 == v2`:
* Returns whether `v1` and `v2` are identical.
* `-v`:
@ -8408,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

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

@ -129,9 +129,9 @@ EM_BOOL CIrrDeviceSDL::MouseLeaveCallback(int eventType, const EmscriptenMouseEv
}
#endif
bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key)
bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE irrlichtKey)
{
switch (key) {
switch (irrlichtKey) {
// keys which are known to have safe special character interpretation
// could need changes over time (removals and additions!)
case KEY_RETURN:
@ -189,24 +189,68 @@ bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key)
}
}
int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key)
int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock)
{
switch (irrlichtKey) {
// special cases that always return a char regardless of how the SDL keycode
// looks
switch (key) {
case KEY_RETURN:
case KEY_ESCAPE:
return (int)key;
return (int)irrlichtKey;
// This is necessary for keys on the numpad because they don't use the same
// keycodes as their non-numpad versions (whose keycodes correspond to chars),
// but have their own SDL keycodes and their own Irrlicht keycodes (which
// don't correspond to chars).
case KEY_MULTIPLY:
return '*';
case KEY_ADD:
return '+';
case KEY_SUBTRACT:
return '-';
case KEY_DIVIDE:
return '/';
default:
break;
}
if (numlock) {
// Number keys on the numpad are also affected, but we only want them
// to produce number chars when numlock is enabled.
switch (irrlichtKey) {
case KEY_NUMPAD0:
return '0';
case KEY_NUMPAD1:
return '1';
case KEY_NUMPAD2:
return '2';
case KEY_NUMPAD3:
return '3';
case KEY_NUMPAD4:
return '4';
case KEY_NUMPAD5:
return '5';
case KEY_NUMPAD6:
return '6';
case KEY_NUMPAD7:
return '7';
case KEY_NUMPAD8:
return '8';
case KEY_NUMPAD9:
return '9';
default:
break;
}
}
// SDL in-place ORs values with no character representation with 1<<30
// https://wiki.libsdl.org/SDL2/SDLKeycodeLookup
if (assumedChar & (1 << 30))
// This also affects the numpad keys btw.
if (sdlKey & (1 << 30))
return 0;
switch (key) {
switch (irrlichtKey) {
case KEY_PRIOR:
case KEY_NEXT:
case KEY_HOME:
@ -218,7 +262,7 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key)
case KEY_NUMLOCK:
return 0;
default:
return assumedChar;
return sdlKey;
}
}
@ -825,7 +869,8 @@ bool CIrrDeviceSDL::run()
irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0;
irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key);
irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key,
(SDL_event.key.keysym.mod & KMOD_NUM) != 0);
postEventFromUser(irrevent);
} break;

@ -273,10 +273,10 @@ class CIrrDeviceSDL : public CIrrDeviceStub
#endif
// Check if a key is a known special character with no side effects on text boxes.
static bool keyIsKnownSpecial(EKEY_CODE key);
static bool keyIsKnownSpecial(EKEY_CODE irrlichtKey);
// Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0).
static int findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key);
static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock);
// Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus.
void resetReceiveTextInputEvents();

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

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

@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h"
#include <algorithm>
#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);
}
/*

@ -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 <quaternion.h>
#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;
}

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

@ -79,6 +79,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "hud.h"
#include "clientdynamicinfo.h"
#include <IAnimatedMeshSceneNode.h>
#include "light_colors.h"
#if USE_SOUND
#include "client/sound/sound_openal.h"
@ -382,6 +383,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float>
m_animation_timer_delta_pixel{"animationTimerDelta"};
CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"};
CachedVertexShaderSetting<float, 3> m_ambient_light{"ambientLight"};
CachedPixelShaderSetting<float, 3> m_minimap_yaw{"yawVec"};
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel{"cameraOffset"};
CachedVertexShaderSetting<float, 3> 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<float, 7> 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.)

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

@ -0,0 +1,99 @@
/*
Minetest
Copyright (C) 2024 Andrey2470T, AndreyT <andreyt2203@gmail.com>
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));
}

61
src/client/light_colors.h Normal file

@ -0,0 +1,61 @@
/*
Minetest
Copyright (C) 2024 Andrey2470T, AndreyT <andreyt2203@gmail.com>
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));

@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm>
#include <cmath>
#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<video::S3DVertexTangents> 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<video::S3DVertexTangents*>(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<u16> 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<u16> 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<v3s16, u8> results;

@ -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<u16> &&vertex_indexes) :
PartialMeshBuffer(scene::SMeshBufferTangents *buffer, std::vector<u16> &&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<u16> m_vertex_indexes;
};
@ -284,52 +284,12 @@ class MapBlockMesh
std::vector<PartialMeshBuffer> 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

@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IAnimatedMesh.h>
#include <SAnimatedMesh.h>
#include <IAnimatedMeshSceneNode.h>
#include <array>
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<typename T>
std::array<T, 24> getCubeVertices(video::SColor c)
{
return std::array<T, 24>{
// 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<video::S3DVertex, 24> vertices = getCubeVertices<video::S3DVertex>(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<video::S3DVertexTangents, 24> vertices = getCubeVertices<video::S3DVertexTangents>(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<video::S3DVertex*>(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<video::S3DVertexTangents*>(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<video::S3DVertexTangents*>(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<video::S3DVertex*>(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<video::S3DVertexTangents*>(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<video::S3DVertex*>(buf->getVertices());
for (u32 i = 0; i < count; i++)
((video::S3DVertex*) (vertices + i * stride))->TCoords = uv[i];
vertices[i].TCoords = uv[i];
}
template <typename F>
template <typename T, typename F>
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<char *>(buf->getVertices());
for (u32 i = 0; i < vertex_count; i++)
fn(reinterpret_cast<video::S3DVertex *>(vertices + i * stride));
T *vertices = static_cast<T*>(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<video::S3DVertexTangents*>(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<video::S3DVertex>(mesh, colorizator);
}
template <float v3f::*U, float v3f::*V>
template <typename T, float v3f::*U, float v3f::*V>
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<T>(mesh, rotator);
}
void rotateMeshXYby(scene::IMesh *mesh, f64 degrees)
{
rotateMesh<&v3f::X, &v3f::Y>(mesh, degrees);
rotateMesh<video::S3DVertex, &v3f::X, &v3f::Y>(mesh, degrees);
}
void rotateMeshXZby(scene::IMesh *mesh, f64 degrees)
{
rotateMesh<&v3f::X, &v3f::Z>(mesh, degrees);
rotateMesh<video::S3DVertex, &v3f::X, &v3f::Z>(mesh, degrees);
}
void rotateMeshTangentsXZby(scene::IMesh *mesh, f64 degrees)
{
rotateMesh<video::S3DVertexTangents, &v3f::X, &v3f::Z>(mesh, degrees);
}
void rotateMeshYZby(scene::IMesh *mesh, f64 degrees)
{
rotateMesh<&v3f::Y, &v3f::Z>(mesh, degrees);
rotateMesh<video::S3DVertex, &v3f::Y, &v3f::Z>(mesh, degrees);
}
void rotateMeshTangentsYZby(scene::IMesh *mesh, f64 degrees)
{
rotateMesh<video::S3DVertexTangents, &v3f::Y, &v3f::Z>(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<video::S3DVertex*>(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<video::S3DVertex2TCoords*>(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<video::S3DVertexTangents*>(mesh_buffer->getVertices());
u16 *indices = mesh_buffer->getIndices();
scene::SMeshBufferTangents *cloned_buffer =
new scene::SMeshBufferTangents();

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

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

@ -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<video::S3DVertexTangents> 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;
}

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

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

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

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