Compare commits

...

16 Commits

Author SHA1 Message Date
Andrey
aa41e44265
Merge b08ee987a6b06d9baedf09ad7c1198c65f935689 into 4c001bd24854b56f6e09372c4ac6870770053f98 2024-06-26 19:07:38 +03: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
24 changed files with 525 additions and 329 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);

@ -8408,6 +8408,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)

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