VBO-related optimizations and improvements (#14395)

This commit is contained in:
sfan5 2024-02-19 19:04:20 +01:00
parent d85c842ce9
commit bb7f57b095
22 changed files with 439 additions and 322 deletions

@ -0,0 +1,17 @@
uniform vec4 fogColor;
uniform float fogDistance;
uniform float fogShadingParameter;
varying vec3 eyeVec;
varying lowp vec4 varColor;
void main(void)
{
vec4 col = varColor;
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col.rgb = mix(fogColor.rgb, col.rgb, clarity);
gl_FragColor = col;
}

@ -0,0 +1,21 @@
uniform vec4 emissiveColor;
varying lowp vec4 varColor;
varying vec3 eyeVec;
void main(void)
{
gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
vec4 color = inVertexColor.bgra;
#else
vec4 color = inVertexColor;
#endif
color *= emissiveColor;
varColor = color;
eyeVec = -(mWorldView * inVertexPosition).xyz;
}

@ -1,6 +1,6 @@
uniform vec4 starColor; uniform vec4 emissiveColor;
void main(void) void main(void)
{ {
gl_FragColor = starColor; gl_FragColor = emissiveColor;
} }

@ -39,53 +39,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm> #include <algorithm>
#include "client/renderingengine.h" #include "client/renderingengine.h"
/*
CAOShaderConstantSetter
*/
//! Shader constant setter for passing material emissive color to the CAO object_shader
class CAOShaderConstantSetter : public IShaderConstantSetter
{
public:
~CAOShaderConstantSetter() override = default;
void onSetConstants(video::IMaterialRendererServices *services) override
{
// Ambient color
video::SColorf emissive_color(m_emissive_color);
float as_array[4] = {
emissive_color.r,
emissive_color.g,
emissive_color.b,
emissive_color.a,
};
m_emissive_color_setting.set(as_array, services);
}
void onSetMaterial(const video::SMaterial& material) override
{
m_emissive_color = material.EmissiveColor;
}
private:
video::SColor m_emissive_color;
CachedPixelShaderSetting<float, 4>
m_emissive_color_setting{"emissiveColor"};
};
class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
{
public:
CAOShaderConstantSetterFactory()
{}
virtual IShaderConstantSetter* create()
{
return new CAOShaderConstantSetter();
}
};
/* /*
ClientEnvironment ClientEnvironment
*/ */
@ -97,8 +50,6 @@ ClientEnvironment::ClientEnvironment(ClientMap *map,
m_texturesource(texturesource), m_texturesource(texturesource),
m_client(client) m_client(client)
{ {
auto *shdrsrc = m_client->getShaderSource();
shdrsrc->addShaderConstantSetterFactory(new CAOShaderConstantSetterFactory());
} }
ClientEnvironment::~ClientEnvironment() ClientEnvironment::~ClientEnvironment()

@ -107,7 +107,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
return false; return false;
} }
if (m_rendering_engine->get_video_driver() == NULL) { if (!m_rendering_engine->get_video_driver()) {
errorstream << "Could not initialize video driver." << std::endl; errorstream << "Could not initialize video driver." << std::endl;
return false; return false;
} }
@ -125,51 +125,16 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
guienv = m_rendering_engine->get_gui_env(); guienv = m_rendering_engine->get_gui_env();
skin = guienv->getSkin(); init_guienv(guienv);
skin->setColor(gui::EGDC_WINDOW_SYMBOL, video::SColor(255, 255, 255, 255));
skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255));
skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0));
skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30));
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0));
skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 120, 50));
skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255));
float density = rangelim(g_settings->getFloat("gui_scaling"), 0.5, 20) *
RenderingEngine::getDisplayDensity();
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * density));
skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(14.0f * density));
skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density));
if (density > 1.5f) {
std::string sprite_path = porting::path_share + "/textures/base/pack/";
if (density > 3.5f)
sprite_path.append("checkbox_64.png");
else if (density > 2.0f)
sprite_path.append("checkbox_32.png");
else
sprite_path.append("checkbox_16.png");
// Texture dimensions should be a power of 2
gui::IGUISpriteBank *sprites = skin->getSpriteBank();
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str());
if (sprite_texture) {
s32 sprite_id = sprites->addTextureAsSprite(sprite_texture);
if (sprite_id != -1)
skin->setIcon(gui::EGDI_CHECK_BOX_CHECKED, sprite_id);
}
}
g_fontengine = new FontEngine(guienv); g_fontengine = new FontEngine(guienv);
FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed."); FATAL_ERROR_IF(!g_fontengine, "Font engine creation failed.");
// Irrlicht 1.8 input colours
skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128));
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49));
// Create the menu clouds // Create the menu clouds
if (!g_menucloudsmgr) // This is only global so it can be used by RenderingEngine::draw_load_screen().
g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager(); assert(!g_menucloudsmgr && !g_menuclouds);
if (!g_menuclouds) g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager();
g_menuclouds = new Clouds(g_menucloudsmgr, -1, rand()); g_menuclouds = new Clouds(g_menucloudsmgr, nullptr, -1, rand());
g_menuclouds->setHeight(100.0f); g_menuclouds->setHeight(100.0f);
g_menuclouds->update(v3f(0, 0, 0), video::SColor(255, 240, 240, 255)); g_menuclouds->update(v3f(0, 0, 0), video::SColor(255, 240, 240, 255));
scene::ICameraSceneNode* camera; scene::ICameraSceneNode* camera;
@ -223,7 +188,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
guiroot = m_rendering_engine->get_gui_env()->addStaticText(L"", guiroot = m_rendering_engine->get_gui_env()->addStaticText(L"",
core::rect<s32>(0, 0, 10000, 10000)); core::rect<s32>(0, 0, 10000, 10000));
bool game_has_run = launch_game(error_message, reconnect_requested, bool should_run_game = launch_game(error_message, reconnect_requested,
start_data, cmd_args); start_data, cmd_args);
// Reset the reconnect_requested flag // Reset the reconnect_requested flag
@ -232,13 +197,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// If skip_main_menu, we only want to startup once // If skip_main_menu, we only want to startup once
if (skip_main_menu && !first_loop) if (skip_main_menu && !first_loop)
break; break;
first_loop = false; first_loop = false;
if (!game_has_run) { if (!should_run_game) {
if (skip_main_menu) if (skip_main_menu)
break; break;
continue; continue;
} }
@ -246,9 +209,6 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
if (!m_rendering_engine->run() || *kill) if (!m_rendering_engine->run() || *kill)
break; break;
m_rendering_engine->get_video_driver()->setTextureCreationFlag(
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
if (g_settings->getBool("enable_touch")) { if (g_settings->getBool("enable_touch")) {
receiver->m_touchscreengui = new TouchScreenGUI(m_rendering_engine->get_raw_device(), receiver); receiver->m_touchscreengui = new TouchScreenGUI(m_rendering_engine->get_raw_device(), receiver);
g_touchscreengui = receiver->m_touchscreengui; g_touchscreengui = receiver->m_touchscreengui;
@ -301,17 +261,18 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// If no main menu, show error and exit // If no main menu, show error and exit
if (skip_main_menu) { if (skip_main_menu) {
if (!error_message.empty()) { if (!error_message.empty())
verbosestream << "error_message = "
<< error_message << std::endl;
retval = false; retval = false;
}
break; break;
} }
} // Menu-game loop } // Menu-game loop
assert(g_menuclouds->getReferenceCount() == 1);
g_menuclouds->drop(); g_menuclouds->drop();
g_menuclouds = nullptr;
assert(g_menucloudsmgr->getReferenceCount() == 1);
g_menucloudsmgr->drop(); g_menucloudsmgr->drop();
g_menucloudsmgr = nullptr;
return retval; return retval;
} }
@ -373,6 +334,45 @@ void ClientLauncher::init_input()
} }
} }
void ClientLauncher::init_guienv(gui::IGUIEnvironment *guienv)
{
gui::IGUISkin *skin = guienv->getSkin();
skin->setColor(gui::EGDC_WINDOW_SYMBOL, video::SColor(255, 255, 255, 255));
skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255));
skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0));
skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30));
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0));
skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 120, 50));
skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255));
skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128));
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49));
float density = rangelim(g_settings->getFloat("gui_scaling"), 0.5f, 20) *
RenderingEngine::getDisplayDensity();
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * density));
skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(14.0f * density));
skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density));
if (density > 1.5f) {
std::string sprite_path = porting::path_share + "/textures/base/pack/";
if (density > 3.5f)
sprite_path.append("checkbox_64.png");
else if (density > 2.0f)
sprite_path.append("checkbox_32.png");
else
sprite_path.append("checkbox_16.png");
// Texture dimensions should be a power of 2
gui::IGUISpriteBank *sprites = skin->getSpriteBank();
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str());
if (sprite_texture) {
s32 sprite_id = sprites->addTextureAsSprite(sprite_texture);
if (sprite_id != -1)
skin->setIcon(gui::EGDI_CHECK_BOX_CHECKED, sprite_id);
}
}
}
bool ClientLauncher::launch_game(std::string &error_message, bool ClientLauncher::launch_game(std::string &error_message,
bool reconnect_requested, GameStartData &start_data, bool reconnect_requested, GameStartData &start_data,
const Settings &cmd_args) const Settings &cmd_args)

@ -38,6 +38,7 @@ private:
void init_args(GameStartData &start_data, const Settings &cmd_args); void init_args(GameStartData &start_data, const Settings &cmd_args);
bool init_engine(); bool init_engine();
void init_input(); void init_input();
void init_guienv(gui::IGUIEnvironment *guienv);
bool launch_game(std::string &error_message, bool reconnect_requested, bool launch_game(std::string &error_message, bool reconnect_requested,
GameStartData &start_data, const Settings &cmd_args); GameStartData &start_data, const Settings &cmd_args);
@ -49,5 +50,4 @@ private:
RenderingEngine *m_rendering_engine = nullptr; RenderingEngine *m_rendering_engine = nullptr;
InputHandler *input = nullptr; InputHandler *input = nullptr;
MyEventReceiver *receiver = nullptr; MyEventReceiver *receiver = nullptr;
gui::IGUISkin *skin = nullptr;
}; };

@ -18,10 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "client/renderingengine.h" #include "client/renderingengine.h"
#include "client/shader.h"
#include "clouds.h" #include "clouds.h"
#include "noise.h"
#include "constants.h" #include "constants.h"
#include "debug.h" #include "debug.h"
#include "irrlicht_changes/printing.h"
#include "noise.h"
#include "profiler.h" #include "profiler.h"
#include "settings.h" #include "settings.h"
#include <cmath> #include <cmath>
@ -40,35 +42,38 @@ static void cloud_3d_setting_changed(const std::string &settingname, void *data)
((Clouds *)data)->readSettings(); ((Clouds *)data)->readSettings();
} }
Clouds::Clouds(scene::ISceneManager* mgr, Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc,
s32 id, s32 id,
u32 seed u32 seed
): ):
scene::ISceneNode(mgr->getRootSceneNode(), mgr, id), scene::ISceneNode(mgr->getRootSceneNode(), mgr, id),
m_seed(seed) m_seed(seed)
{ {
m_enable_shaders = g_settings->getBool("enable_shaders");
// menu clouds use shader-less clouds for simplicity (ssrc == NULL)
m_enable_shaders = m_enable_shaders && ssrc;
m_material.Lighting = false; m_material.Lighting = false;
m_material.BackfaceCulling = true; m_material.BackfaceCulling = true;
m_material.FogEnable = true; m_material.FogEnable = true;
m_material.AntiAliasing = video::EAAM_SIMPLE; m_material.AntiAliasing = video::EAAM_SIMPLE;
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; if (m_enable_shaders) {
m_material.forEachTexture([] (auto &tex) { auto sid = ssrc->getShader("cloud_shader", TILE_MATERIAL_ALPHA);
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; m_material.MaterialType = ssrc->getShaderInfo(sid).material;
tex.MagFilter = video::ETMAGF_NEAREST; } else {
}); m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
m_params.height = 120; m_params = SkyboxDefaults::getCloudDefaults();
m_params.density = 0.4f;
m_params.thickness = 16.0f;
m_params.color_bright = video::SColor(229, 240, 240, 255);
m_params.color_ambient = video::SColor(255, 0, 0, 0);
m_params.speed = v2f(0.0f, -2.0f);
readSettings(); readSettings();
g_settings->registerChangedCallback("enable_3d_clouds", g_settings->registerChangedCallback("enable_3d_clouds",
&cloud_3d_setting_changed, this); &cloud_3d_setting_changed, this);
updateBox(); updateBox();
m_meshbuffer.reset(new scene::SMeshBuffer());
m_meshbuffer->setHardwareMappingHint(scene::EHM_DYNAMIC);
} }
Clouds::~Clouds() Clouds::~Clouds()
@ -82,38 +87,14 @@ void Clouds::OnRegisterSceneNode()
if(IsVisible) if(IsVisible)
{ {
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
//SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
} }
ISceneNode::OnRegisterSceneNode(); ISceneNode::OnRegisterSceneNode();
} }
void Clouds::render() void Clouds::updateMesh()
{ {
// Clouds move from Z+ towards Z-
if (m_params.density <= 0.0f)
return; // no need to do anything
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
//if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_SOLID)
return;
ScopeProfiler sp(g_profiler, "Clouds::render()", SPT_AVG);
int num_faces_to_draw = m_enable_3d ? 6 : 1;
m_material.BackfaceCulling = m_enable_3d;
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->setMaterial(m_material);
/*
Clouds move from Z+ towards Z-
*/
const float cloud_full_radius = cloud_size * m_cloud_radius_i;
v2f camera_pos_2d(m_camera_pos.X, m_camera_pos.Z); v2f camera_pos_2d(m_camera_pos.X, m_camera_pos.Z);
// Position of cloud noise origin from the camera // Position of cloud noise origin from the camera
@ -126,56 +107,61 @@ void Clouds::render()
std::floor(center_of_drawing_in_noise_f.Y / cloud_size) std::floor(center_of_drawing_in_noise_f.Y / cloud_size)
); );
// Only update mesh if it has moved enough, this saves lots of GPU buffer uploads.
constexpr float max_d = 5 * BS;
if (!m_mesh_valid) {
// mesh was never created or invalidated
} else if (m_mesh_origin.getDistanceFrom(m_origin) >= max_d) {
// clouds moved
} else if (center_of_drawing_in_noise_i != m_last_noise_center) {
// noise offset changed
// I think in practice this never happens due to the camera offset
// being smaller than the cloud size.(?)
} else {
return;
}
ScopeProfiler sp(g_profiler, "Clouds::updateMesh()", SPT_AVG);
m_mesh_origin = m_origin;
m_last_noise_center = center_of_drawing_in_noise_i;
m_mesh_valid = true;
const u32 num_faces_to_draw = m_enable_3d ? 6 : 1;
// The world position of the integer center point of drawing in the noise // The world position of the integer center point of drawing in the noise
v2f world_center_of_drawing_in_noise_f = v2f( v2f world_center_of_drawing_in_noise_f = v2f(
center_of_drawing_in_noise_i.X * cloud_size, center_of_drawing_in_noise_i.X * cloud_size,
center_of_drawing_in_noise_i.Y * cloud_size center_of_drawing_in_noise_i.Y * cloud_size
) + m_origin; ) + m_origin;
/*video::SColor c_top(128,b*240,b*240,b*255); // Colors with primitive shading
video::SColor c_side_1(128,b*230,b*230,b*255);
video::SColor c_side_2(128,b*220,b*220,b*245);
video::SColor c_bottom(128,b*205,b*205,b*230);*/
video::SColorf c_top_f(m_color); video::SColorf c_top_f(m_color);
video::SColorf c_side_1_f(m_color); video::SColorf c_side_1_f(m_color);
video::SColorf c_side_2_f(m_color); video::SColorf c_side_2_f(m_color);
video::SColorf c_bottom_f(m_color); video::SColorf c_bottom_f(m_color);
c_side_1_f.r *= 0.95; if (m_enable_shaders) {
c_side_1_f.g *= 0.95; // shader mixes the base color, set via EmissiveColor
c_side_1_f.b *= 0.95; c_top_f = c_side_1_f = c_side_2_f = c_bottom_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
c_side_2_f.r *= 0.90; }
c_side_2_f.g *= 0.90; c_side_1_f.r *= 0.95f;
c_side_2_f.b *= 0.90; c_side_1_f.g *= 0.95f;
c_bottom_f.r *= 0.80; c_side_1_f.b *= 0.95f;
c_bottom_f.g *= 0.80; c_side_2_f.r *= 0.90f;
c_bottom_f.b *= 0.80; c_side_2_f.g *= 0.90f;
c_side_2_f.b *= 0.90f;
c_bottom_f.r *= 0.80f;
c_bottom_f.g *= 0.80f;
c_bottom_f.b *= 0.80f;
video::SColor c_top = c_top_f.toSColor(); video::SColor c_top = c_top_f.toSColor();
video::SColor c_side_1 = c_side_1_f.toSColor(); video::SColor c_side_1 = c_side_1_f.toSColor();
video::SColor c_side_2 = c_side_2_f.toSColor(); video::SColor c_side_2 = c_side_2_f.toSColor();
video::SColor c_bottom = c_bottom_f.toSColor(); video::SColor c_bottom = c_bottom_f.toSColor();
// Get fog parameters for setting them back later
video::SColor fog_color(0,0,0,0);
video::E_FOG_TYPE fog_type = video::EFT_FOG_LINEAR;
f32 fog_start = 0;
f32 fog_end = 0;
f32 fog_density = 0;
bool fog_pixelfog = false;
bool fog_rangefog = false;
driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
fog_pixelfog, fog_rangefog);
// Set our own fog, unless it was already disabled
if (fog_start < FOG_RANGE_ALL) {
driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
}
// Read noise // Read noise
std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2); std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
std::vector<video::S3DVertex> vertices;
vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);
for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) { for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i; u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
@ -190,10 +176,23 @@ void Clouds::render()
} }
} }
auto *mb = m_meshbuffer.get();
{
const u32 vertex_count = num_faces_to_draw * 16 * m_cloud_radius_i * m_cloud_radius_i;
const u32 quad_count = vertex_count / 4;
const u32 index_count = quad_count * 6;
// reserve memory
mb->Vertices.reallocate(vertex_count);
mb->Indices.reallocate(index_count);
}
#define GETINDEX(x, z, radius) (((z)+(radius))*(radius)*2 + (x)+(radius)) #define GETINDEX(x, z, radius) (((z)+(radius))*(radius)*2 + (x)+(radius))
#define INAREA(x, z, radius) \ #define INAREA(x, z, radius) \
((x) >= -(radius) && (x) < (radius) && (z) >= -(radius) && (z) < (radius)) ((x) >= -(radius) && (x) < (radius) && (z) >= -(radius) && (z) < (radius))
mb->Vertices.set_used(0);
for (s16 zi0= -m_cloud_radius_i; zi0 < m_cloud_radius_i; zi0++) for (s16 zi0= -m_cloud_radius_i; zi0 < m_cloud_radius_i; zi0++)
for (s16 xi0= -m_cloud_radius_i; xi0 < m_cloud_radius_i; xi0++) for (s16 xi0= -m_cloud_radius_i; xi0 < m_cloud_radius_i; xi0++)
{ {
@ -224,7 +223,7 @@ void Clouds::render()
const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f; const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
const f32 rz = cloud_size / 2; const f32 rz = cloud_size / 2;
for(int i=0; i<num_faces_to_draw; i++) for(u32 i = 0; i < num_faces_to_draw; i++)
{ {
switch(i) switch(i)
{ {
@ -310,27 +309,87 @@ void Clouds::render()
} }
v3f pos(p0.X, m_params.height * BS, p0.Y); v3f pos(p0.X, m_params.height * BS, p0.Y);
pos -= intToFloat(m_camera_offset, BS);
for (video::S3DVertex &vertex : v) { for (video::S3DVertex &vertex : v) {
vertex.Pos += pos; vertex.Pos += pos;
vertices.push_back(vertex); mb->Vertices.push_back(vertex);
} }
} }
} }
int quad_count = vertices.size() / 4; mb->setDirty(scene::EBT_VERTEX);
std::vector<u16> indices;
indices.reserve(quad_count * 6); const u32 quad_count = mb->getVertexCount() / 4;
for (int k = 0; k < quad_count; k++) { const u32 index_count = quad_count * 6;
indices.push_back(4 * k + 0); // rewrite index array as needed
indices.push_back(4 * k + 1); if (mb->getIndexCount() > index_count) {
indices.push_back(4 * k + 2); mb->Indices.set_used(index_count);
indices.push_back(4 * k + 2); mb->setDirty(scene::EBT_INDEX);
indices.push_back(4 * k + 3); } else if (mb->getIndexCount() < index_count) {
indices.push_back(4 * k + 0); const u32 start = mb->getIndexCount() / 6;
assert(start * 6 == mb->getIndexCount());
for (u32 k = start; k < quad_count; k++) {
mb->Indices.push_back(4 * k + 0);
mb->Indices.push_back(4 * k + 1);
mb->Indices.push_back(4 * k + 2);
mb->Indices.push_back(4 * k + 2);
mb->Indices.push_back(4 * k + 3);
mb->Indices.push_back(4 * k + 0);
}
mb->setDirty(scene::EBT_INDEX);
} }
driver->drawVertexPrimitiveList(vertices.data(), vertices.size(), indices.data(), 2 * quad_count,
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT); tracestream << "Cloud::updateMesh(): " << mb->getVertexCount() << " vertices"
<< std::endl;
}
void Clouds::render()
{
if (m_params.density <= 0.0f)
return; // no need to do anything
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if (SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT)
return;
updateMesh();
// Update position
{
v2f off_origin = m_origin - m_mesh_origin;
v3f rel(off_origin.X, 0, off_origin.Y);
rel -= intToFloat(m_camera_offset, BS);
setPosition(rel);
updateAbsolutePosition();
}
m_material.BackfaceCulling = m_enable_3d;
if (m_enable_shaders)
m_material.EmissiveColor = m_color.toSColor();
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
driver->setMaterial(m_material);
const float cloud_full_radius = cloud_size * m_cloud_radius_i;
// Get fog parameters for setting them back later
video::SColor fog_color(0,0,0,0);
video::E_FOG_TYPE fog_type = video::EFT_FOG_LINEAR;
f32 fog_start = 0;
f32 fog_end = 0;
f32 fog_density = 0;
bool fog_pixelfog = false;
bool fog_rangefog = false;
driver->getFog(fog_color, fog_type, fog_start, fog_end, fog_density,
fog_pixelfog, fog_rangefog);
// Set our own fog, unless it was already disabled
if (fog_start < FOG_RANGE_ALL) {
driver->setFog(fog_color, fog_type, cloud_full_radius * 0.5,
cloud_full_radius*1.2, fog_density, fog_pixelfog, fog_rangefog);
}
driver->drawMeshBuffer(m_meshbuffer.get());
// Restore fog settings // Restore fog settings
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density, driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
@ -346,13 +405,13 @@ void Clouds::update(const v3f &camera_p, const video::SColorf &color_diffuse)
{ {
video::SColorf ambient(m_params.color_ambient); video::SColorf ambient(m_params.color_ambient);
video::SColorf bright(m_params.color_bright); video::SColorf bright(m_params.color_bright);
m_camera_pos = camera_p;
m_color.r = core::clamp(color_diffuse.r * bright.r, ambient.r, 1.0f); m_color.r = core::clamp(color_diffuse.r * bright.r, ambient.r, 1.0f);
m_color.g = core::clamp(color_diffuse.g * bright.g, ambient.g, 1.0f); m_color.g = core::clamp(color_diffuse.g * bright.g, ambient.g, 1.0f);
m_color.b = core::clamp(color_diffuse.b * bright.b, ambient.b, 1.0f); m_color.b = core::clamp(color_diffuse.b * bright.b, ambient.b, 1.0f);
m_color.a = bright.a; m_color.a = bright.a;
// is the camera inside the cloud mesh? // is the camera inside the cloud mesh?
m_camera_pos = camera_p;
m_camera_inside_cloud = false; // default m_camera_inside_cloud = false; // default
if (m_enable_3d) { if (m_enable_3d) {
float camera_height = camera_p.Y - BS * m_camera_offset.Y; float camera_height = camera_p.Y - BS * m_camera_offset.Y;
@ -369,9 +428,14 @@ void Clouds::update(const v3f &camera_p, const video::SColorf &color_diffuse)
void Clouds::readSettings() void Clouds::readSettings()
{ {
// Upper limit was chosen due to posible render bugs // The code isn't designed to go over 64k vertices so the upper limits were
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, 62); // chosen to avoid exactly that.
// refer to vertex_count in updateMesh()
m_enable_3d = g_settings->getBool("enable_3d_clouds"); m_enable_3d = g_settings->getBool("enable_3d_clouds");
const u16 maximum = m_enable_3d ? 62 : 25;
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum);
invalidateMesh();
} }
bool Clouds::gridFilled(int x, int y) const bool Clouds::gridFilled(int x, int y) const

@ -19,10 +19,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once #pragma once
#include "irrlichttypes_extrabloated.h"
#include <iostream>
#include "constants.h" #include "constants.h"
#include "irr_ptr.h"
#include "irrlichttypes_extrabloated.h"
#include "skyparams.h" #include "skyparams.h"
#include <iostream>
class IShaderSource;
// Menu clouds // Menu clouds
class Clouds; class Clouds;
@ -34,7 +37,7 @@ extern scene::ISceneManager *g_menucloudsmgr;
class Clouds : public scene::ISceneNode class Clouds : public scene::ISceneNode
{ {
public: public:
Clouds(scene::ISceneManager* mgr, Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc,
s32 id, s32 id,
u32 seed u32 seed
); );
@ -72,7 +75,7 @@ public:
void update(const v3f &camera_p, const video::SColorf &color); void update(const v3f &camera_p, const video::SColorf &color);
void updateCameraOffset(const v3s16 &camera_offset) void updateCameraOffset(v3s16 camera_offset)
{ {
m_camera_offset = camera_offset; m_camera_offset = camera_offset;
updateBox(); updateBox();
@ -82,24 +85,29 @@ public:
void setDensity(float density) void setDensity(float density)
{ {
if (m_params.density == density)
return;
m_params.density = density; m_params.density = density;
// currently does not need bounding invalidateMesh();
} }
void setColorBright(const video::SColor &color_bright) void setColorBright(video::SColor color_bright)
{ {
m_params.color_bright = color_bright; m_params.color_bright = color_bright;
} }
void setColorAmbient(const video::SColor &color_ambient) void setColorAmbient(video::SColor color_ambient)
{ {
m_params.color_ambient = color_ambient; m_params.color_ambient = color_ambient;
} }
void setHeight(float height) void setHeight(float height)
{ {
m_params.height = height; // add bounding when necessary if (m_params.height == height)
return;
m_params.height = height;
updateBox(); updateBox();
invalidateMesh();
} }
void setSpeed(v2f speed) void setSpeed(v2f speed)
@ -109,8 +117,11 @@ public:
void setThickness(float thickness) void setThickness(float thickness)
{ {
if (m_params.thickness == thickness)
return;
m_params.thickness = thickness; m_params.thickness = thickness;
updateBox(); updateBox();
invalidateMesh();
} }
bool isCameraInsideCloud() const { return m_camera_inside_cloud; } bool isCameraInsideCloud() const { return m_camera_inside_cloud; }
@ -126,18 +137,33 @@ private:
BS * 1000000.0f, height_bs + thickness_bs - BS * m_camera_offset.Y, BS * 1000000.0f); BS * 1000000.0f, height_bs + thickness_bs - BS * m_camera_offset.Y, BS * 1000000.0f);
} }
void updateMesh();
void invalidateMesh()
{
m_mesh_valid = false;
}
bool gridFilled(int x, int y) const; bool gridFilled(int x, int y) const;
video::SMaterial m_material; video::SMaterial m_material;
irr_ptr<scene::SMeshBuffer> m_meshbuffer;
// Value of m_origin at the time the mesh was last updated
v2f m_mesh_origin;
// Value of center_of_drawing_in_noise_i at the time the mesh was last updated
v2s16 m_last_noise_center;
// Was the mesh ever generated?
bool m_mesh_valid = false;
aabb3f m_box; aabb3f m_box;
v2f m_origin;
u16 m_cloud_radius_i; u16 m_cloud_radius_i;
bool m_enable_3d;
u32 m_seed; u32 m_seed;
v3f m_camera_pos; v3f m_camera_pos;
v2f m_origin;
v3s16 m_camera_offset; v3s16 m_camera_offset;
video::SColorf m_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
CloudParams m_params;
bool m_camera_inside_cloud = false; bool m_camera_inside_cloud = false;
bool m_enable_shaders, m_enable_3d;
video::SColorf m_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
CloudParams m_params;
}; };

@ -812,7 +812,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
(m_prop.visual == "wielditem")); (m_prop.visual == "wielditem"));
m_wield_meshnode->setScale(m_prop.visual_size / 2.0f); m_wield_meshnode->setScale(m_prop.visual_size / 2.0f);
m_wield_meshnode->setColor(video::SColor(0xFFFFFFFF));
} else { } else {
infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual infostream<<"GenericCAO::addToScene(): \""<<m_prop.visual
<<"\" not supported"<<std::endl; <<"\" not supported"<<std::endl;

@ -379,7 +379,6 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float> CachedPixelShaderSetting<float>
m_animation_timer_delta_pixel{"animationTimerDelta"}; m_animation_timer_delta_pixel{"animationTimerDelta"};
CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"}; CachedPixelShaderSetting<float, 3> m_day_light{"dayLight"};
CachedPixelShaderSetting<float, 4> m_star_color{"starColor"};
CachedPixelShaderSetting<float, 3> m_eye_position_pixel{"eyePosition"}; CachedPixelShaderSetting<float, 3> m_eye_position_pixel{"eyePosition"};
CachedVertexShaderSetting<float, 3> m_eye_position_vertex{"eyePosition"}; CachedVertexShaderSetting<float, 3> m_eye_position_vertex{"eyePosition"};
CachedPixelShaderSetting<float, 3> m_minimap_yaw{"yawVec"}; CachedPixelShaderSetting<float, 3> m_minimap_yaw{"yawVec"};
@ -473,10 +472,6 @@ public:
get_sunlight_color(&sunlight, daynight_ratio); get_sunlight_color(&sunlight, daynight_ratio);
m_day_light.set(sunlight, services); m_day_light.set(sunlight, services);
video::SColorf star_color = m_sky->getCurrentStarColor();
float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
m_star_color.set(clr, services);
u32 animation_timer = m_client->getEnv().getFrameTime() % 1000000; u32 animation_timer = m_client->getEnv().getFrameTime() % 1000000;
float animation_timer_f = (float)animation_timer / 100000.f; float animation_timer_f = (float)animation_timer / 100000.f;
m_animation_timer_vertex.set(&animation_timer_f, services); m_animation_timer_vertex.set(&animation_timer_f, services);
@ -529,7 +524,9 @@ public:
m_bloom_radius_pixel.set(&m_bloom_radius, services); m_bloom_radius_pixel.set(&m_bloom_radius, services);
m_bloom_strength_pixel.set(&m_bloom_strength, services); m_bloom_strength_pixel.set(&m_bloom_strength, services);
} }
float saturation = m_client->getEnv().getLocalPlayer()->getLighting().saturation;
const auto &lighting = m_client->getEnv().getLocalPlayer()->getLighting();
float saturation = lighting.saturation;
m_saturation_pixel.set(&saturation, services); m_saturation_pixel.set(&saturation, services);
if (m_volumetric_light_enabled) { if (m_volumetric_light_enabled) {
@ -540,13 +537,13 @@ public:
if (m_sky->getSunVisible()) { if (m_sky->getSunVisible()) {
v3f sun_position = camera_node->getAbsolutePosition() + v3f sun_position = camera_node->getAbsolutePosition() +
10000. * m_sky->getSunDirection(); 10000.f * m_sky->getSunDirection();
transform.transformVect(sun_position); transform.transformVect(sun_position);
sun_position.normalize(); sun_position.normalize();
m_sun_position_pixel.set(sun_position, services); m_sun_position_pixel.set(sun_position, services);
float sun_brightness = rangelim(107.143f * m_sky->getSunDirection().dotProduct(v3f(0.f, 1.f, 0.f)), 0.f, 1.f); float sun_brightness = core::clamp(107.143f * m_sky->getSunDirection().Y, 0.f, 1.f);
m_sun_brightness_pixel.set(&sun_brightness, services); m_sun_brightness_pixel.set(&sun_brightness, services);
} else { } else {
m_sun_position_pixel.set(v3f(0.f, 0.f, -1.f), services); m_sun_position_pixel.set(v3f(0.f, 0.f, -1.f), services);
@ -557,13 +554,13 @@ public:
if (m_sky->getMoonVisible()) { if (m_sky->getMoonVisible()) {
v3f moon_position = camera_node->getAbsolutePosition() + v3f moon_position = camera_node->getAbsolutePosition() +
10000. * m_sky->getMoonDirection(); 10000.f * m_sky->getMoonDirection();
transform.transformVect(moon_position); transform.transformVect(moon_position);
moon_position.normalize(); moon_position.normalize();
m_moon_position_pixel.set(moon_position, services); m_moon_position_pixel.set(moon_position, services);
float moon_brightness = rangelim(107.143f * m_sky->getMoonDirection().dotProduct(v3f(0.f, 1.f, 0.f)), 0.f, 1.f); float moon_brightness = core::clamp(107.143f * m_sky->getMoonDirection().Y, 0.f, 1.f);
m_moon_brightness_pixel.set(&moon_brightness, services); m_moon_brightness_pixel.set(&moon_brightness, services);
} else { } else {
m_moon_position_pixel.set(v3f(0.f, 0.f, -1.f), services); m_moon_position_pixel.set(v3f(0.f, 0.f, -1.f), services);
@ -571,7 +568,8 @@ public:
float moon_brightness = 0.f; float moon_brightness = 0.f;
m_moon_brightness_pixel.set(&moon_brightness, services); m_moon_brightness_pixel.set(&moon_brightness, services);
} }
float volumetric_light_strength = m_client->getEnv().getLocalPlayer()->getLighting().volumetric_light_strength;
float volumetric_light_strength = lighting.volumetric_light_strength;
m_volumetric_light_strength_pixel.set(&volumetric_light_strength, services); m_volumetric_light_strength_pixel.set(&volumetric_light_strength, services);
} }
} }
@ -1099,6 +1097,8 @@ bool Game::startup(bool *kill,
driver = device->getVideoDriver(); driver = device->getVideoDriver();
smgr = m_rendering_engine->get_scene_manager(); smgr = m_rendering_engine->get_scene_manager();
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true); smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
// Reinit runData // Reinit runData
@ -1454,7 +1454,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Clouds /* Clouds
*/ */
if (m_cache_enable_clouds) if (m_cache_enable_clouds)
clouds = new Clouds(smgr, -1, time(0)); clouds = new Clouds(smgr, shader_src, -1, rand());
/* Skybox /* Skybox
*/ */

@ -97,7 +97,7 @@ Hud::Hud(Client *client, LocalPlayer *player,
if (g_settings->getBool("enable_shaders")) { if (g_settings->getBool("enable_shaders")) {
IShaderSource *shdrsrc = client->getShaderSource(); IShaderSource *shdrsrc = client->getShaderSource();
u16 shader_id = shdrsrc->getShader( auto shader_id = shdrsrc->getShader(
m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", TILE_MATERIAL_ALPHA); m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", TILE_MATERIAL_ALPHA);
m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
} else { } else {
@ -1100,24 +1100,23 @@ void drawItemStack(
video::SColor basecolor = video::SColor basecolor =
client->idef()->getItemstackColor(item, client); client->idef()->getItemstackColor(item, client);
u32 mc = mesh->getMeshBufferCount(); const u32 mc = mesh->getMeshBufferCount();
if (mc > imesh->buffer_colors.size())
imesh->buffer_colors.resize(mc);
for (u32 j = 0; j < mc; ++j) { for (u32 j = 0; j < mc; ++j) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
// we can modify vertices relatively fast,
// because these meshes are not buffered.
assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
video::SColor c = basecolor; video::SColor c = basecolor;
if (imesh->buffer_colors.size() > j) { auto &p = imesh->buffer_colors[j];
ItemPartColor *p = &imesh->buffer_colors[j]; p.applyOverride(c);
if (p->override_base)
c = p->color;
}
if (imesh->needs_shading) if (p.needColorize(c)) {
colorizeMeshBuffer(buf, &c); buf->setDirty(scene::EBT_VERTEX);
else if (imesh->needs_shading)
setMeshBufferColor(buf, c); colorizeMeshBuffer(buf, &c);
else
setMeshBufferColor(buf, c);
}
video::SMaterial &material = buf->getMaterial(); video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;

@ -615,7 +615,7 @@ void Minimap::drawMinimap(core::rect<s32> rect)
material.TextureLayers[1].Texture = data->heightmap_texture; material.TextureLayers[1].Texture = data->heightmap_texture;
if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) { if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) {
u16 sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA); auto sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA);
material.MaterialType = m_shdrsrc->getShaderInfo(sid).material; material.MaterialType = m_shdrsrc->getShaderInfo(sid).material;
} else { } else {
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;

@ -94,7 +94,7 @@ class FogShaderConstantSetter : public IShaderConstantSetter
public: public:
void onSetConstants(video::IMaterialRendererServices *services) override void onSetConstants(video::IMaterialRendererServices *services) override
{ {
auto *driver = RenderingEngine::get_video_driver(); auto *driver = services->getVideoDriver();
assert(driver); assert(driver);
video::SColor fog_color(0); video::SColor fog_color(0);
@ -314,15 +314,17 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
gui::StaticText::add(guienv, text, textrect, false, false); gui::StaticText::add(guienv, text, textrect, false, false);
guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT); guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
if (sky && g_settings->getBool("menu_clouds")) { auto *driver = get_video_driver();
g_menuclouds->step(dtime * 3);
g_menuclouds->render(); if (sky) {
get_video_driver()->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR); driver->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR);
g_menucloudsmgr->drawAll(); if (g_settings->getBool("menu_clouds")) {
} else if (sky) g_menuclouds->step(dtime * 3);
get_video_driver()->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR); g_menucloudsmgr->drawAll();
else }
get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0)); } else {
driver->beginScene(true, true, video::SColor(255, 0, 0, 0));
}
// draw progress bar // draw progress bar
if ((percent >= 0) && (percent <= 100)) { if ((percent >= 0) && (percent <= 100)) {
@ -367,7 +369,7 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
} }
guienv->drawAll(); guienv->drawAll();
get_video_driver()->endScene(); driver->endScene();
guitext->remove(); guitext->remove();
} }

@ -90,7 +90,6 @@ public:
bool setupTopLevelWindow(); bool setupTopLevelWindow();
bool setWindowIcon(); bool setWindowIcon();
static bool print_video_modes();
void cleanupMeshCache(); void cleanupMeshCache();
void removeMesh(const scene::IMesh* mesh); void removeMesh(const scene::IMesh* mesh);

@ -217,13 +217,22 @@ class MainShaderConstantSetter : public IShaderConstantSetter
// Texture matrix // Texture matrix
CachedVertexShaderSetting<float, 16> m_texture{"mTexture"}; CachedVertexShaderSetting<float, 16> m_texture{"mTexture"};
// commonly used way to pass material color to shader
video::SColor m_emissive_color;
CachedPixelShaderSetting<float, 4> m_emissive_color_setting{"emissiveColor"};
public: public:
~MainShaderConstantSetter() = default; ~MainShaderConstantSetter() = default;
virtual void onSetMaterial(const video::SMaterial& material) override
{
m_emissive_color = material.EmissiveColor;
}
virtual void onSetConstants(video::IMaterialRendererServices *services) override virtual void onSetConstants(video::IMaterialRendererServices *services) override
{ {
video::IVideoDriver *driver = services->getVideoDriver(); video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver); assert(driver);
// Set world matrix // Set world matrix
core::matrix4 world = driver->getTransform(video::ETS_WORLD); core::matrix4 world = driver->getTransform(video::ETS_WORLD);
@ -244,6 +253,9 @@ public:
m_world_view.set(worldView, services); m_world_view.set(worldView, services);
m_texture.set(texture, services); m_texture.set(texture, services);
} }
video::SColorf emissive_color(m_emissive_color);
m_emissive_color_setting.set(emissive_color, services);
} }
}; };
@ -545,11 +557,11 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
return shaderinfo; return shaderinfo;
video::IVideoDriver *driver = RenderingEngine::get_video_driver(); video::IVideoDriver *driver = RenderingEngine::get_video_driver();
if (!driver->queryFeature(video::EVDF_ARB_GLSL)) { video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
if (!driver->queryFeature(video::EVDF_ARB_GLSL) || !gpu) {
throw ShaderException(gettext("Shaders are enabled but GLSL is not " throw ShaderException(gettext("Shaders are enabled but GLSL is not "
"supported by the driver.")); "supported by the driver."));
} }
video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
// Create shaders header // Create shaders header
bool fully_programmable = driver->getDriverType() == video::EDT_OGLES2 || driver->getDriverType() == video::EDT_OPENGL3; bool fully_programmable = driver->getDriverType() == video::EDT_OGLES2 || driver->getDriverType() == video::EDT_OPENGL3;
@ -610,14 +622,6 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
#define textureFlags texture2 #define textureFlags texture2
)"; )";
// Since this is the first time we're using the GL bindings be extra careful.
// This should be removed before 5.6.0 or similar.
if (!GL.GetString) {
errorstream << "OpenGL procedures were not loaded correctly, "
"please open a bug report with details about your platform/OS." << std::endl;
abort();
}
bool use_discard = fully_programmable; bool use_discard = fully_programmable;
// For renderers that should use discard instead of GL_ALPHA_TEST // For renderers that should use discard instead of GL_ALPHA_TEST
const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER)); const char *renderer = reinterpret_cast<const char*>(GL.GetString(GL.RENDERER));

@ -77,6 +77,7 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade
// Create materials // Create materials
m_materials[0] = baseMaterial(); m_materials[0] = baseMaterial();
// FIXME: shouldn't this check m_enable_shaders?
m_materials[0].MaterialType = ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material; m_materials[0].MaterialType = ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material;
m_materials[0].Lighting = true; m_materials[0].Lighting = true;
m_materials[0].ColorMaterial = video::ECM_NONE; m_materials[0].ColorMaterial = video::ECM_NONE;
@ -683,11 +684,12 @@ void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day)
float starbrightness = (0.25f - std::abs(tod)) * 20.0f; float starbrightness = (0.25f - std::abs(tod)) * 20.0f;
float alpha = clamp(starbrightness, day_opacity, 1.0f); float alpha = clamp(starbrightness, day_opacity, 1.0f);
m_star_color = m_star_params.starcolor; video::SColorf color(m_star_params.starcolor);
m_star_color.a *= alpha; color.a *= alpha;
if (m_star_color.a <= 0.0f) // Stars are only drawn when not fully transparent if (color.a <= 0.0f) // Stars are only drawn when not fully transparent
return; return;
m_materials[0].DiffuseColor = m_materials[0].EmissiveColor = m_star_color.toSColor(); m_materials[0].EmissiveColor = color.toSColor();
auto sky_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f)); auto sky_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f));
auto world_matrix = driver->getTransform(video::ETS_WORLD); auto world_matrix = driver->getTransform(video::ETS_WORLD);
driver->setTransform(video::ETS_WORLD, world_matrix * sky_rotation); driver->setTransform(video::ETS_WORLD, world_matrix * sky_rotation);

@ -114,7 +114,6 @@ public:
void clearSkyboxTextures() { m_sky_params.textures.clear(); } void clearSkyboxTextures() { m_sky_params.textures.clear(); }
void addTextureToSkybox(const std::string &texture, int material_id, void addTextureToSkybox(const std::string &texture, int material_id,
ITextureSource *tsrc); ITextureSource *tsrc);
const video::SColorf &getCurrentStarColor() const { return m_star_color; }
// Note: the Sky class doesn't use these values. It just stores them. // Note: the Sky class doesn't use these values. It just stores them.
void setFogDistance(s16 fog_distance) { m_sky_params.fog_distance = fog_distance; } void setFogDistance(s16 fog_distance) { m_sky_params.fog_distance = fog_distance; }
@ -210,7 +209,6 @@ private:
u64 m_seed = 0; u64 m_seed = 0;
irr_ptr<scene::SMeshBuffer> m_stars; irr_ptr<scene::SMeshBuffer> m_stars;
video::SColorf m_star_color;
video::ITexture *m_sun_texture; video::ITexture *m_sun_texture;
video::ITexture *m_moon_texture; video::ITexture *m_moon_texture;

@ -508,21 +508,26 @@ void WieldMeshSceneNode::setColor(video::SColor c)
u8 red = c.getRed(); u8 red = c.getRed();
u8 green = c.getGreen(); u8 green = c.getGreen();
u8 blue = c.getBlue(); u8 blue = c.getBlue();
u32 mc = mesh->getMeshBufferCount();
const u32 mc = mesh->getMeshBufferCount();
if (mc > m_colors.size())
m_colors.resize(mc);
for (u32 j = 0; j < mc; j++) { for (u32 j = 0; j < mc; j++) {
video::SColor bc(m_base_color); video::SColor bc(m_base_color);
if ((m_colors.size() > j) && (m_colors[j].override_base)) m_colors[j].applyOverride(bc);
bc = m_colors[j].color;
video::SColor buffercolor(255, video::SColor buffercolor(255,
bc.getRed() * red / 255, bc.getRed() * red / 255,
bc.getGreen() * green / 255, bc.getGreen() * green / 255,
bc.getBlue() * blue / 255); bc.getBlue() * blue / 255);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
if (m_enable_shaders) if (m_colors[j].needColorize(buffercolor)) {
setMeshBufferColor(buf, buffercolor); buf->setDirty(scene::EBT_VERTEX);
else if (m_enable_shaders)
colorizeMeshBuffer(buf, &buffercolor); setMeshBufferColor(buf, buffercolor);
else
colorizeMeshBuffer(buf, &buffercolor);
}
} }
} }
@ -536,8 +541,7 @@ void WieldMeshSceneNode::setNodeLightColor(video::SColor color)
video::SMaterial &material = m_meshnode->getMaterial(i); video::SMaterial &material = m_meshnode->getMaterial(i);
material.EmissiveColor = color; material.EmissiveColor = color;
} }
} } else {
else {
setColor(color); setColor(color);
} }
} }
@ -557,6 +561,12 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
dummymesh->drop(); // m_meshnode grabbed it dummymesh->drop(); // m_meshnode grabbed it
} else { } else {
m_meshnode->setMesh(mesh); m_meshnode->setMesh(mesh);
// without shaders recolored often for lighting
// otherwise only once
if (m_enable_shaders)
mesh->setHardwareMappingHint(scene::EHM_STATIC);
else
mesh->setHardwareMappingHint(scene::EHM_DYNAMIC);
} }
m_meshnode->forEachMaterial([this] (auto &mat) { m_meshnode->forEachMaterial([this] (auto &mat) {
@ -651,8 +661,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
} }
} }
u32 mc = mesh->getMeshBufferCount(); for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
for (u32 i = 0; i < mc; ++i) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
video::SMaterial &material = buf->getMaterial(); video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@ -668,6 +677,12 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
rotateMeshXZby(mesh, -45); rotateMeshXZby(mesh, -45);
rotateMeshYZby(mesh, -30); rotateMeshYZby(mesh, -30);
} }
// might need to be re-colorized, this is done only when needed
if (mesh) {
mesh->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_VERTEX);
mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_INDEX);
}
result->mesh = mesh; result->mesh = mesh;
} }
@ -722,11 +737,10 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
bool use_shaders, bool set_material, const video::E_MATERIAL_TYPE *mattype, bool use_shaders, bool set_material, const video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors, bool apply_scale) std::vector<ItemPartColor> *colors, bool apply_scale)
{ {
u32 mc = mesh->getMeshBufferCount(); const u32 mc = mesh->getMeshBufferCount();
// Allocate colors for existing buffers // Allocate colors for existing buffers
colors->clear(); colors->clear();
for (u32 i = 0; i < mc; ++i) colors->resize(mc);
colors->push_back(ItemPartColor());
for (u32 i = 0; i < mc; ++i) { for (u32 i = 0; i < mc; ++i) {
const TileSpec *tile = &(f.tiles[i]); const TileSpec *tile = &(f.tiles[i]);
@ -741,11 +755,11 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
mesh->addMeshBuffer(copy); mesh->addMeshBuffer(copy);
copy->drop(); copy->drop();
buf = copy; buf = copy;
colors->push_back( colors->emplace_back(layer->has_color, layer->color);
ItemPartColor(layer->has_color, layer->color));
} else { } else {
(*colors)[i] = ItemPartColor(layer->has_color, layer->color); (*colors)[i] = ItemPartColor(layer->has_color, layer->color);
} }
video::SMaterial &material = buf->getMaterial(); video::SMaterial &material = buf->getMaterial();
if (set_material) if (set_material)
layer->applyMaterialOptions(material); layer->applyMaterialOptions(material);
@ -768,6 +782,7 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
} }
material.setTexture(2, layer->flags_texture); material.setTexture(2, layer->flags_texture);
} }
if (apply_scale && tile->world_aligned) { if (apply_scale && tile->world_aligned) {
u32 n = buf->getVertexCount(); u32 n = buf->getVertexCount();
for (u32 k = 0; k != n; ++k) for (u32 k = 0; k != n; ++k)

@ -29,38 +29,54 @@ class ITextureSource;
struct ContentFeatures; struct ContentFeatures;
class ShadowRenderer; class ShadowRenderer;
/*! /*
* Holds color information of an item mesh's buffer. * Holds color information of an item mesh's buffer.
*/ */
struct ItemPartColor class ItemPartColor
{ {
/*! /*
* If this is false, the global base color of the item * Optional color that overrides the global base color.
* will be used instead of the specific color of the
* buffer.
*/ */
bool override_base = false; video::SColor override_color;
/*! /*
* The color of the buffer. * Stores the last color this mesh buffer was colorized as.
*/ */
video::SColor color = 0; video::SColor last_colorized;
// saves some bytes compared to two std::optionals
bool override_color_set = false;
bool last_colorized_set = false;
public:
ItemPartColor() = default; ItemPartColor() = default;
ItemPartColor(bool override, video::SColor color) : ItemPartColor(bool override, video::SColor color) :
override_base(override), color(color) override_color(color), override_color_set(override)
{ {}
void applyOverride(video::SColor &dest) const {
if (override_color_set)
dest = override_color;
}
bool needColorize(video::SColor target) {
if (last_colorized_set && target == last_colorized)
return false;
last_colorized_set = true;
last_colorized = target;
return true;
} }
}; };
struct ItemMesh struct ItemMesh
{ {
scene::IMesh *mesh = nullptr; scene::IMesh *mesh = nullptr;
/*! /*
* Stores the color of each mesh buffer. * Stores the color of each mesh buffer.
*/ */
std::vector<ItemPartColor> buffer_colors; std::vector<ItemPartColor> buffer_colors;
/*! /*
* If false, all faces of the item should have the same brightness. * If false, all faces of the item should have the same brightness.
* Disables shading based on normal vectors. * Disables shading based on normal vectors.
*/ */

@ -19,25 +19,26 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiEngine.h" #include "guiEngine.h"
#include <IGUIStaticText.h>
#include <ICameraSceneNode.h>
#include "client/renderingengine.h"
#include "scripting_mainmenu.h"
#include "config.h"
#include "version.h"
#include "porting.h"
#include "filesys.h"
#include "settings.h"
#include "guiMainMenu.h"
#include "sound.h"
#include "httpfetch.h"
#include "log.h"
#include "client/fontengine.h" #include "client/fontengine.h"
#include "client/guiscalingfilter.h" #include "client/guiscalingfilter.h"
#include "irrlicht_changes/static_text.h" #include "client/renderingengine.h"
#include "client/shader.h"
#include "client/tile.h" #include "client/tile.h"
#include "config.h"
#include "content/content.h" #include "content/content.h"
#include "content/mods.h" #include "content/mods.h"
#include "filesys.h"
#include "guiMainMenu.h"
#include "httpfetch.h"
#include "irrlicht_changes/static_text.h"
#include "log.h"
#include "porting.h"
#include "scripting_mainmenu.h"
#include "settings.h"
#include "sound.h"
#include "version.h"
#include <ICameraSceneNode.h>
#include <IGUIStaticText.h>
#if USE_SOUND #if USE_SOUND
#include "client/sound/sound_openal.h" #include "client/sound/sound_openal.h"
@ -139,6 +140,10 @@ GUIEngine::GUIEngine(JoystickController *joystick,
// create texture source // create texture source
m_texture_source = std::make_unique<MenuTextureSource>(rendering_engine->get_video_driver()); m_texture_source = std::make_unique<MenuTextureSource>(rendering_engine->get_video_driver());
// create shader source
// (currently only used by clouds)
m_shader_source.reset(createShaderSource());
// create soundmanager // create soundmanager
#if USE_SOUND #if USE_SOUND
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) { if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) {
@ -285,10 +290,10 @@ bool GUIEngine::loadMainMenuScript()
void GUIEngine::run() void GUIEngine::run()
{ {
IrrlichtDevice *device = m_rendering_engine->get_raw_device(); IrrlichtDevice *device = m_rendering_engine->get_raw_device();
video::IVideoDriver *driver = device->getVideoDriver();
// Always create clouds because they may or may not be // Always create clouds because they may or may not be
// needed based on the game selected // needed based on the game selected
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
cloudInit(); cloudInit();
unsigned int text_height = g_fontengine->getTextHeight(); unsigned int text_height = g_fontengine->getTextHeight();
@ -375,23 +380,24 @@ GUIEngine::~GUIEngine()
m_sound_manager.reset(); m_sound_manager.reset();
m_irr_toplefttext->setText(L""); m_irr_toplefttext->remove();
//clean up texture pointers m_cloud.clouds.reset();
// delete textures
for (image_definition &texture : m_textures) { for (image_definition &texture : m_textures) {
if (texture.texture) if (texture.texture)
m_rendering_engine->get_video_driver()->removeTexture(texture.texture); m_rendering_engine->get_video_driver()->removeTexture(texture.texture);
} }
m_texture_source.reset();
m_cloud.clouds.reset();
} }
/******************************************************************************/ /******************************************************************************/
void GUIEngine::cloudInit() void GUIEngine::cloudInit()
{ {
m_cloud.clouds = make_irr<Clouds>(m_smgr, -1, rand()); m_shader_source->addShaderConstantSetterFactory(
new FogShaderConstantSetterFactory());
m_cloud.clouds = make_irr<Clouds>(m_smgr, m_shader_source.get(), -1, rand());
m_cloud.clouds->setHeight(100.0f); m_cloud.clouds->setHeight(100.0f);
m_cloud.clouds->update(v3f(0, 0, 0), video::SColor(255,240,240,255)); m_cloud.clouds->update(v3f(0, 0, 0), video::SColor(255,240,240,255));
@ -404,7 +410,6 @@ void GUIEngine::cloudInit()
void GUIEngine::drawClouds(float dtime) void GUIEngine::drawClouds(float dtime)
{ {
m_cloud.clouds->step(dtime*3); m_cloud.clouds->step(dtime*3);
m_cloud.clouds->render();
m_smgr->drawAll(); m_smgr->drawAll();
} }

@ -54,6 +54,7 @@ struct image_definition {
class GUIEngine; class GUIEngine;
class RenderingEngine; class RenderingEngine;
class MainMenuScripting; class MainMenuScripting;
class IWritableShaderSource;
struct MainMenuData; struct MainMenuData;
/******************************************************************************/ /******************************************************************************/
@ -203,7 +204,9 @@ private:
MainMenuData *m_data = nullptr; MainMenuData *m_data = nullptr;
/** texture source */ /** texture source */
std::unique_ptr<ISimpleTextureSource> m_texture_source; std::unique_ptr<ISimpleTextureSource> m_texture_source;
/** sound manager*/ /** shader source */
std::unique_ptr<IWritableShaderSource> m_shader_source;
/** sound manager */
std::unique_ptr<ISoundManager> m_sound_manager; std::unique_ptr<ISoundManager> m_sound_manager;
/** representation of form source to be used in mainmenu formspec */ /** representation of form source to be used in mainmenu formspec */

@ -466,10 +466,6 @@ public:
if (!inventory_image.empty()) if (!inventory_image.empty())
cc->inventory_texture = tsrc->getTexture(inventory_image); cc->inventory_texture = tsrc->getTexture(inventory_image);
getItemMesh(client, item, &(cc->wield_mesh)); getItemMesh(client, item, &(cc->wield_mesh));
// note: vertices are modified frequently (see hud.cpp) so only indices
// can be mapped
if (auto mesh = cc->wield_mesh.mesh)
mesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_INDEX);
cc->palette = tsrc->getPalette(def.palette_image); cc->palette = tsrc->getPalette(def.palette_image);