diff --git a/client/shaders/cloud_shader/opengl_fragment.glsl b/client/shaders/cloud_shader/opengl_fragment.glsl new file mode 100644 index 000000000..fe416d121 --- /dev/null +++ b/client/shaders/cloud_shader/opengl_fragment.glsl @@ -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; +} diff --git a/client/shaders/cloud_shader/opengl_vertex.glsl b/client/shaders/cloud_shader/opengl_vertex.glsl new file mode 100644 index 000000000..4bc6eb65e --- /dev/null +++ b/client/shaders/cloud_shader/opengl_vertex.glsl @@ -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; +} diff --git a/client/shaders/stars_shader/opengl_fragment.glsl b/client/shaders/stars_shader/opengl_fragment.glsl index a9ed741bf..209b6dc89 100644 --- a/client/shaders/stars_shader/opengl_fragment.glsl +++ b/client/shaders/stars_shader/opengl_fragment.glsl @@ -1,6 +1,6 @@ -uniform vec4 starColor; +uniform vec4 emissiveColor; void main(void) { - gl_FragColor = starColor; + gl_FragColor = emissiveColor; } diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index af815c015..7e1676ffe 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -39,53 +39,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #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 - m_emissive_color_setting{"emissiveColor"}; -}; - -class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory -{ -public: - CAOShaderConstantSetterFactory() - {} - - virtual IShaderConstantSetter* create() - { - return new CAOShaderConstantSetter(); - } -}; - /* ClientEnvironment */ @@ -97,8 +50,6 @@ ClientEnvironment::ClientEnvironment(ClientMap *map, m_texturesource(texturesource), m_client(client) { - auto *shdrsrc = m_client->getShaderSource(); - shdrsrc->addShaderConstantSetterFactory(new CAOShaderConstantSetterFactory()); } ClientEnvironment::~ClientEnvironment() diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index c23a1e3e9..b5ba4ccc8 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -107,7 +107,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) 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; return false; } @@ -125,51 +125,16 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); guienv = m_rendering_engine->get_gui_env(); - 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)); - - 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); - } - } + init_guienv(guienv); g_fontengine = new FontEngine(guienv); - FATAL_ERROR_IF(g_fontengine == NULL, "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)); + FATAL_ERROR_IF(!g_fontengine, "Font engine creation failed."); // Create the menu clouds - if (!g_menucloudsmgr) - g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager(); - if (!g_menuclouds) - g_menuclouds = new Clouds(g_menucloudsmgr, -1, rand()); + // This is only global so it can be used by RenderingEngine::draw_load_screen(). + assert(!g_menucloudsmgr && !g_menuclouds); + g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager(); + g_menuclouds = new Clouds(g_menucloudsmgr, nullptr, -1, rand()); g_menuclouds->setHeight(100.0f); g_menuclouds->update(v3f(0, 0, 0), video::SColor(255, 240, 240, 255)); 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"", core::rect(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); // 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 && !first_loop) break; - first_loop = false; - if (!game_has_run) { + if (!should_run_game) { if (skip_main_menu) break; - continue; } @@ -246,9 +209,6 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) if (!m_rendering_engine->run() || *kill) break; - m_rendering_engine->get_video_driver()->setTextureCreationFlag( - video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map")); - if (g_settings->getBool("enable_touch")) { receiver->m_touchscreengui = new TouchScreenGUI(m_rendering_engine->get_raw_device(), receiver); 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 (skip_main_menu) { - if (!error_message.empty()) { - verbosestream << "error_message = " - << error_message << std::endl; + if (!error_message.empty()) retval = false; - } break; } } // Menu-game loop + assert(g_menuclouds->getReferenceCount() == 1); g_menuclouds->drop(); + g_menuclouds = nullptr; + assert(g_menucloudsmgr->getReferenceCount() == 1); g_menucloudsmgr->drop(); + g_menucloudsmgr = nullptr; 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 reconnect_requested, GameStartData &start_data, const Settings &cmd_args) diff --git a/src/client/clientlauncher.h b/src/client/clientlauncher.h index 395f83b9d..dc0794c88 100644 --- a/src/client/clientlauncher.h +++ b/src/client/clientlauncher.h @@ -38,6 +38,7 @@ private: void init_args(GameStartData &start_data, const Settings &cmd_args); bool init_engine(); void init_input(); + void init_guienv(gui::IGUIEnvironment *guienv); bool launch_game(std::string &error_message, bool reconnect_requested, GameStartData &start_data, const Settings &cmd_args); @@ -49,5 +50,4 @@ private: RenderingEngine *m_rendering_engine = nullptr; InputHandler *input = nullptr; MyEventReceiver *receiver = nullptr; - gui::IGUISkin *skin = nullptr; }; diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index f07c2bcaf..3ab504371 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -18,10 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "client/renderingengine.h" +#include "client/shader.h" #include "clouds.h" -#include "noise.h" #include "constants.h" #include "debug.h" +#include "irrlicht_changes/printing.h" +#include "noise.h" #include "profiler.h" #include "settings.h" #include @@ -40,35 +42,38 @@ static void cloud_3d_setting_changed(const std::string &settingname, void *data) ((Clouds *)data)->readSettings(); } -Clouds::Clouds(scene::ISceneManager* mgr, +Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc, s32 id, u32 seed ): scene::ISceneNode(mgr->getRootSceneNode(), mgr, id), 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.BackfaceCulling = true; m_material.FogEnable = true; m_material.AntiAliasing = video::EAAM_SIMPLE; - m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - m_material.forEachTexture([] (auto &tex) { - tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; - tex.MagFilter = video::ETMAGF_NEAREST; - }); + if (m_enable_shaders) { + auto sid = ssrc->getShader("cloud_shader", TILE_MATERIAL_ALPHA); + m_material.MaterialType = ssrc->getShaderInfo(sid).material; + } else { + m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + } - m_params.height = 120; - 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); + m_params = SkyboxDefaults::getCloudDefaults(); readSettings(); g_settings->registerChangedCallback("enable_3d_clouds", &cloud_3d_setting_changed, this); updateBox(); + + m_meshbuffer.reset(new scene::SMeshBuffer()); + m_meshbuffer->setHardwareMappingHint(scene::EHM_DYNAMIC); } Clouds::~Clouds() @@ -82,38 +87,14 @@ void Clouds::OnRegisterSceneNode() if(IsVisible) { SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); - //SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); } ISceneNode::OnRegisterSceneNode(); } -void Clouds::render() +void Clouds::updateMesh() { - - 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; + // Clouds move from Z+ towards Z- v2f camera_pos_2d(m_camera_pos.X, m_camera_pos.Z); // 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) ); + // 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 v2f world_center_of_drawing_in_noise_f = v2f( center_of_drawing_in_noise_i.X * cloud_size, center_of_drawing_in_noise_i.Y * cloud_size ) + m_origin; - /*video::SColor c_top(128,b*240,b*240,b*255); - 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);*/ + // Colors with primitive shading + video::SColorf c_top_f(m_color); video::SColorf c_side_1_f(m_color); video::SColorf c_side_2_f(m_color); video::SColorf c_bottom_f(m_color); - c_side_1_f.r *= 0.95; - c_side_1_f.g *= 0.95; - c_side_1_f.b *= 0.95; - c_side_2_f.r *= 0.90; - c_side_2_f.g *= 0.90; - c_side_2_f.b *= 0.90; - c_bottom_f.r *= 0.80; - c_bottom_f.g *= 0.80; - c_bottom_f.b *= 0.80; + if (m_enable_shaders) { + // shader mixes the base color, set via EmissiveColor + 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_1_f.r *= 0.95f; + c_side_1_f.g *= 0.95f; + c_side_1_f.b *= 0.95f; + c_side_2_f.r *= 0.90f; + 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_side_1 = c_side_1_f.toSColor(); video::SColor c_side_2 = c_side_2_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 std::vector grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2); - std::vector 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++) { 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 INAREA(x, 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 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 rz = cloud_size / 2; - for(int i=0; iVertices.push_back(vertex); } } } - int quad_count = vertices.size() / 4; - std::vector indices; - indices.reserve(quad_count * 6); - for (int k = 0; k < quad_count; k++) { - indices.push_back(4 * k + 0); - indices.push_back(4 * k + 1); - indices.push_back(4 * k + 2); - indices.push_back(4 * k + 2); - indices.push_back(4 * k + 3); - indices.push_back(4 * k + 0); + mb->setDirty(scene::EBT_VERTEX); + + const u32 quad_count = mb->getVertexCount() / 4; + const u32 index_count = quad_count * 6; + // rewrite index array as needed + if (mb->getIndexCount() > index_count) { + mb->Indices.set_used(index_count); + mb->setDirty(scene::EBT_INDEX); + } else if (mb->getIndexCount() < index_count) { + 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 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 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.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.a = bright.a; // is the camera inside the cloud mesh? + m_camera_pos = camera_p; m_camera_inside_cloud = false; // default if (m_enable_3d) { 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() { - // Upper limit was chosen due to posible render bugs - m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, 62); + // The code isn't designed to go over 64k vertices so the upper limits were + // chosen to avoid exactly that. + // refer to vertex_count in updateMesh() m_enable_3d = g_settings->getBool("enable_3d_clouds"); + const u16 maximum = m_enable_3d ? 62 : 25; + m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum); + + invalidateMesh(); } bool Clouds::gridFilled(int x, int y) const diff --git a/src/client/clouds.h b/src/client/clouds.h index 6db88d93c..23273a3c9 100644 --- a/src/client/clouds.h +++ b/src/client/clouds.h @@ -19,10 +19,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once -#include "irrlichttypes_extrabloated.h" -#include #include "constants.h" +#include "irr_ptr.h" +#include "irrlichttypes_extrabloated.h" #include "skyparams.h" +#include + +class IShaderSource; // Menu clouds class Clouds; @@ -34,7 +37,7 @@ extern scene::ISceneManager *g_menucloudsmgr; class Clouds : public scene::ISceneNode { public: - Clouds(scene::ISceneManager* mgr, + Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc, s32 id, u32 seed ); @@ -72,7 +75,7 @@ public: 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; updateBox(); @@ -82,24 +85,29 @@ public: void setDensity(float density) { + if (m_params.density == density) + return; 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; } - void setColorAmbient(const video::SColor &color_ambient) + void setColorAmbient(video::SColor color_ambient) { m_params.color_ambient = color_ambient; } void setHeight(float height) { - m_params.height = height; // add bounding when necessary + if (m_params.height == height) + return; + m_params.height = height; updateBox(); + invalidateMesh(); } void setSpeed(v2f speed) @@ -109,8 +117,11 @@ public: void setThickness(float thickness) { + if (m_params.thickness == thickness) + return; m_params.thickness = thickness; updateBox(); + invalidateMesh(); } 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); } + void updateMesh(); + void invalidateMesh() + { + m_mesh_valid = false; + } + bool gridFilled(int x, int y) const; video::SMaterial m_material; + irr_ptr 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; + v2f m_origin; u16 m_cloud_radius_i; - bool m_enable_3d; u32 m_seed; v3f m_camera_pos; - v2f m_origin; + 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_enable_shaders, m_enable_3d; + video::SColorf m_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); + CloudParams m_params; }; diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 330eebd95..6506521a3 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -812,7 +812,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) (m_prop.visual == "wielditem")); m_wield_meshnode->setScale(m_prop.visual_size / 2.0f); - m_wield_meshnode->setColor(video::SColor(0xFFFFFFFF)); } else { infostream<<"GenericCAO::addToScene(): \""< m_animation_timer_delta_pixel{"animationTimerDelta"}; CachedPixelShaderSetting m_day_light{"dayLight"}; - CachedPixelShaderSetting m_star_color{"starColor"}; CachedPixelShaderSetting m_eye_position_pixel{"eyePosition"}; CachedVertexShaderSetting m_eye_position_vertex{"eyePosition"}; CachedPixelShaderSetting m_minimap_yaw{"yawVec"}; @@ -473,10 +472,6 @@ public: get_sunlight_color(&sunlight, daynight_ratio); 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; float animation_timer_f = (float)animation_timer / 100000.f; 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_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); if (m_volumetric_light_enabled) { @@ -540,13 +537,13 @@ public: if (m_sky->getSunVisible()) { v3f sun_position = camera_node->getAbsolutePosition() + - 10000. * m_sky->getSunDirection(); + 10000.f * m_sky->getSunDirection(); transform.transformVect(sun_position); sun_position.normalize(); 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); } else { m_sun_position_pixel.set(v3f(0.f, 0.f, -1.f), services); @@ -557,13 +554,13 @@ public: if (m_sky->getMoonVisible()) { v3f moon_position = camera_node->getAbsolutePosition() + - 10000. * m_sky->getMoonDirection(); + 10000.f * m_sky->getMoonDirection(); transform.transformVect(moon_position); moon_position.normalize(); 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); } else { m_moon_position_pixel.set(v3f(0.f, 0.f, -1.f), services); @@ -571,7 +568,8 @@ public: float moon_brightness = 0.f; 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); } } @@ -1099,6 +1097,8 @@ bool Game::startup(bool *kill, driver = device->getVideoDriver(); 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); // Reinit runData @@ -1454,7 +1454,7 @@ bool Game::createClient(const GameStartData &start_data) /* Clouds */ if (m_cache_enable_clouds) - clouds = new Clouds(smgr, -1, time(0)); + clouds = new Clouds(smgr, shader_src, -1, rand()); /* Skybox */ diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 9439a4492..e1641366e 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -97,7 +97,7 @@ Hud::Hud(Client *client, LocalPlayer *player, if (g_settings->getBool("enable_shaders")) { 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_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; } else { @@ -1100,24 +1100,23 @@ void drawItemStack( video::SColor basecolor = 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) { 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; - if (imesh->buffer_colors.size() > j) { - ItemPartColor *p = &imesh->buffer_colors[j]; - if (p->override_base) - c = p->color; - } + auto &p = imesh->buffer_colors[j]; + p.applyOverride(c); - if (imesh->needs_shading) - colorizeMeshBuffer(buf, &c); - else - setMeshBufferColor(buf, c); + if (p.needColorize(c)) { + buf->setDirty(scene::EBT_VERTEX); + if (imesh->needs_shading) + colorizeMeshBuffer(buf, &c); + else + setMeshBufferColor(buf, c); + } video::SMaterial &material = buf->getMaterial(); material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 852220d06..afac89843 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -615,7 +615,7 @@ void Minimap::drawMinimap(core::rect rect) material.TextureLayers[1].Texture = data->heightmap_texture; 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; } else { material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 59c1a086f..debfe8e21 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -94,7 +94,7 @@ class FogShaderConstantSetter : public IShaderConstantSetter public: void onSetConstants(video::IMaterialRendererServices *services) override { - auto *driver = RenderingEngine::get_video_driver(); + auto *driver = services->getVideoDriver(); assert(driver); 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); guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT); - if (sky && g_settings->getBool("menu_clouds")) { - g_menuclouds->step(dtime * 3); - g_menuclouds->render(); - get_video_driver()->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR); - g_menucloudsmgr->drawAll(); - } else if (sky) - get_video_driver()->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR); - else - get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0)); + auto *driver = get_video_driver(); + + if (sky) { + driver->beginScene(true, true, RenderingEngine::MENU_SKY_COLOR); + if (g_settings->getBool("menu_clouds")) { + g_menuclouds->step(dtime * 3); + g_menucloudsmgr->drawAll(); + } + } else { + driver->beginScene(true, true, video::SColor(255, 0, 0, 0)); + } // draw progress bar if ((percent >= 0) && (percent <= 100)) { @@ -367,7 +369,7 @@ void RenderingEngine::draw_load_screen(const std::wstring &text, } guienv->drawAll(); - get_video_driver()->endScene(); + driver->endScene(); guitext->remove(); } diff --git a/src/client/renderingengine.h b/src/client/renderingengine.h index e787af488..948485d82 100644 --- a/src/client/renderingengine.h +++ b/src/client/renderingengine.h @@ -90,7 +90,6 @@ public: bool setupTopLevelWindow(); bool setWindowIcon(); - static bool print_video_modes(); void cleanupMeshCache(); void removeMesh(const scene::IMesh* mesh); diff --git a/src/client/shader.cpp b/src/client/shader.cpp index ed4f618fe..c6de1ee35 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -217,13 +217,22 @@ class MainShaderConstantSetter : public IShaderConstantSetter // Texture matrix CachedVertexShaderSetting m_texture{"mTexture"}; + // commonly used way to pass material color to shader + video::SColor m_emissive_color; + CachedPixelShaderSetting m_emissive_color_setting{"emissiveColor"}; + public: ~MainShaderConstantSetter() = default; + virtual void onSetMaterial(const video::SMaterial& material) override + { + m_emissive_color = material.EmissiveColor; + } + virtual void onSetConstants(video::IMaterialRendererServices *services) override { video::IVideoDriver *driver = services->getVideoDriver(); - sanity_check(driver); + assert(driver); // Set world matrix core::matrix4 world = driver->getTransform(video::ETS_WORLD); @@ -244,6 +253,9 @@ public: m_world_view.set(worldView, 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; 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 " "supported by the driver.")); } - video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices(); // Create shaders header 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 )"; - // 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; // For renderers that should use discard instead of GL_ALPHA_TEST const char *renderer = reinterpret_cast(GL.GetString(GL.RENDERER)); diff --git a/src/client/sky.cpp b/src/client/sky.cpp index 12eb7f0e8..d7e99fff7 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -77,6 +77,7 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade // Create materials 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].Lighting = true; 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 alpha = clamp(starbrightness, day_opacity, 1.0f); - m_star_color = m_star_params.starcolor; - m_star_color.a *= alpha; - if (m_star_color.a <= 0.0f) // Stars are only drawn when not fully transparent + video::SColorf color(m_star_params.starcolor); + color.a *= alpha; + if (color.a <= 0.0f) // Stars are only drawn when not fully transparent 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 world_matrix = driver->getTransform(video::ETS_WORLD); driver->setTransform(video::ETS_WORLD, world_matrix * sky_rotation); diff --git a/src/client/sky.h b/src/client/sky.h index c9064c038..2eadea561 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -114,7 +114,6 @@ public: void clearSkyboxTextures() { m_sky_params.textures.clear(); } void addTextureToSkybox(const std::string &texture, int material_id, ITextureSource *tsrc); - const video::SColorf &getCurrentStarColor() const { return m_star_color; } // 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; } @@ -210,7 +209,6 @@ private: u64 m_seed = 0; irr_ptr m_stars; - video::SColorf m_star_color; video::ITexture *m_sun_texture; video::ITexture *m_moon_texture; diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index c89f3bd4a..02039aa1c 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -508,21 +508,26 @@ void WieldMeshSceneNode::setColor(video::SColor c) u8 red = c.getRed(); u8 green = c.getGreen(); 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++) { video::SColor bc(m_base_color); - if ((m_colors.size() > j) && (m_colors[j].override_base)) - bc = m_colors[j].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); - if (m_enable_shaders) - setMeshBufferColor(buf, buffercolor); - else - colorizeMeshBuffer(buf, &buffercolor); + if (m_colors[j].needColorize(buffercolor)) { + buf->setDirty(scene::EBT_VERTEX); + if (m_enable_shaders) + setMeshBufferColor(buf, buffercolor); + else + colorizeMeshBuffer(buf, &buffercolor); + } } } @@ -536,8 +541,7 @@ void WieldMeshSceneNode::setNodeLightColor(video::SColor color) video::SMaterial &material = m_meshnode->getMaterial(i); material.EmissiveColor = color; } - } - else { + } else { setColor(color); } } @@ -557,6 +561,12 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh) dummymesh->drop(); // m_meshnode grabbed it } else { 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) { @@ -651,8 +661,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) } } - u32 mc = mesh->getMeshBufferCount(); - for (u32 i = 0; i < mc; ++i) { + for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) { scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); video::SMaterial &material = buf->getMaterial(); material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -668,6 +677,12 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) rotateMeshXZby(mesh, -45); 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; } @@ -722,11 +737,10 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, bool use_shaders, bool set_material, const video::E_MATERIAL_TYPE *mattype, std::vector *colors, bool apply_scale) { - u32 mc = mesh->getMeshBufferCount(); + const u32 mc = mesh->getMeshBufferCount(); // Allocate colors for existing buffers colors->clear(); - for (u32 i = 0; i < mc; ++i) - colors->push_back(ItemPartColor()); + colors->resize(mc); for (u32 i = 0; i < mc; ++i) { const TileSpec *tile = &(f.tiles[i]); @@ -741,11 +755,11 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, mesh->addMeshBuffer(copy); copy->drop(); buf = copy; - colors->push_back( - ItemPartColor(layer->has_color, layer->color)); + colors->emplace_back(layer->has_color, layer->color); } else { (*colors)[i] = ItemPartColor(layer->has_color, layer->color); } + video::SMaterial &material = buf->getMaterial(); if (set_material) layer->applyMaterialOptions(material); @@ -768,6 +782,7 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, } material.setTexture(2, layer->flags_texture); } + if (apply_scale && tile->world_aligned) { u32 n = buf->getVertexCount(); for (u32 k = 0; k != n; ++k) diff --git a/src/client/wieldmesh.h b/src/client/wieldmesh.h index be0867e43..6358a6665 100644 --- a/src/client/wieldmesh.h +++ b/src/client/wieldmesh.h @@ -29,38 +29,54 @@ class ITextureSource; struct ContentFeatures; class ShadowRenderer; -/*! +/* * Holds color information of an item mesh's buffer. */ -struct ItemPartColor +class ItemPartColor { - /*! - * If this is false, the global base color of the item - * will be used instead of the specific color of the - * buffer. + /* + * Optional color that overrides the global base color. */ - bool override_base = false; - /*! - * The color of the buffer. + video::SColor override_color; + /* + * 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(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 { scene::IMesh *mesh = nullptr; - /*! + /* * Stores the color of each mesh buffer. */ std::vector buffer_colors; - /*! + /* * If false, all faces of the item should have the same brightness. * Disables shading based on normal vectors. */ diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp index a0e4055b8..923ca4bcd 100644 --- a/src/gui/guiEngine.cpp +++ b/src/gui/guiEngine.cpp @@ -19,25 +19,26 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "guiEngine.h" -#include -#include -#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/guiscalingfilter.h" -#include "irrlicht_changes/static_text.h" +#include "client/renderingengine.h" +#include "client/shader.h" #include "client/tile.h" +#include "config.h" #include "content/content.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 +#include #if USE_SOUND #include "client/sound/sound_openal.h" @@ -139,6 +140,10 @@ GUIEngine::GUIEngine(JoystickController *joystick, // create texture source m_texture_source = std::make_unique(rendering_engine->get_video_driver()); + // create shader source + // (currently only used by clouds) + m_shader_source.reset(createShaderSource()); + // create soundmanager #if USE_SOUND if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) { @@ -285,10 +290,10 @@ bool GUIEngine::loadMainMenuScript() void GUIEngine::run() { IrrlichtDevice *device = m_rendering_engine->get_raw_device(); + video::IVideoDriver *driver = device->getVideoDriver(); + // Always create clouds because they may or may not be // needed based on the game selected - video::IVideoDriver *driver = m_rendering_engine->get_video_driver(); - cloudInit(); unsigned int text_height = g_fontengine->getTextHeight(); @@ -375,23 +380,24 @@ GUIEngine::~GUIEngine() 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) { if (texture.texture) m_rendering_engine->get_video_driver()->removeTexture(texture.texture); } - - m_texture_source.reset(); - - m_cloud.clouds.reset(); } /******************************************************************************/ void GUIEngine::cloudInit() { - m_cloud.clouds = make_irr(m_smgr, -1, rand()); + m_shader_source->addShaderConstantSetterFactory( + new FogShaderConstantSetterFactory()); + + m_cloud.clouds = make_irr(m_smgr, m_shader_source.get(), -1, rand()); m_cloud.clouds->setHeight(100.0f); 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) { m_cloud.clouds->step(dtime*3); - m_cloud.clouds->render(); m_smgr->drawAll(); } diff --git a/src/gui/guiEngine.h b/src/gui/guiEngine.h index eb3e01f62..688648be1 100644 --- a/src/gui/guiEngine.h +++ b/src/gui/guiEngine.h @@ -54,6 +54,7 @@ struct image_definition { class GUIEngine; class RenderingEngine; class MainMenuScripting; +class IWritableShaderSource; struct MainMenuData; /******************************************************************************/ @@ -203,7 +204,9 @@ private: MainMenuData *m_data = nullptr; /** texture source */ std::unique_ptr m_texture_source; - /** sound manager*/ + /** shader source */ + std::unique_ptr m_shader_source; + /** sound manager */ std::unique_ptr m_sound_manager; /** representation of form source to be used in mainmenu formspec */ diff --git a/src/itemdef.cpp b/src/itemdef.cpp index bd08f1e2b..363b94983 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -466,10 +466,6 @@ public: if (!inventory_image.empty()) cc->inventory_texture = tsrc->getTexture(inventory_image); 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);