]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/shader.cpp
Update Android defaults for modern H/W. (#7572)
[dragonfireclient.git] / src / shader.cpp
index ef15f29ba303dfb41dca6b7aeb4519ff832f5a8c..3b49a36bad48c25f6753e1f0bb61a9314c6dd010 100644 (file)
@@ -18,25 +18,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
+#include <fstream>
+#include <iterator>
 #include "shader.h"
 #include "irrlichttypes_extrabloated.h"
 #include "debug.h"
 #include "shader.h"
 #include "irrlichttypes_extrabloated.h"
 #include "debug.h"
-#include "main.h" // for g_settings
 #include "filesys.h"
 #include "util/container.h"
 #include "util/thread.h"
 #include "settings.h"
 #include "filesys.h"
 #include "util/container.h"
 #include "util/thread.h"
 #include "settings.h"
-#include <iterator>
 #include <ICameraSceneNode.h>
 #include <IGPUProgrammingServices.h>
 #include <IMaterialRenderer.h>
 #include <IMaterialRendererServices.h>
 #include <IShaderConstantSetCallBack.h>
 #include <ICameraSceneNode.h>
 #include <IGPUProgrammingServices.h>
 #include <IMaterialRenderer.h>
 #include <IMaterialRendererServices.h>
 #include <IShaderConstantSetCallBack.h>
+#include "client/renderingengine.h"
 #include "EShaderTypes.h"
 #include "log.h"
 #include "gamedef.h"
 #include "EShaderTypes.h"
 #include "log.h"
 #include "gamedef.h"
-#include "strfnd.h" // trim()
-#include "tile.h"
+#include "client/tile.h"
 
 /*
        A cache from shader name to shader path
 
 /*
        A cache from shader name to shader path
@@ -56,7 +56,7 @@ std::string getShaderPath(const std::string &name_of_shader,
                const std::string &filename)
 {
        std::string combined = name_of_shader + DIR_DELIM + filename;
                const std::string &filename)
 {
        std::string combined = name_of_shader + DIR_DELIM + filename;
-       std::string fullpath = "";
+       std::string fullpath;
        /*
                Check from cache
        */
        /*
                Check from cache
        */
@@ -68,8 +68,7 @@ std::string getShaderPath(const std::string &name_of_shader,
                Check from shader_path
        */
        std::string shader_path = g_settings->get("shader_path");
                Check from shader_path
        */
        std::string shader_path = g_settings->get("shader_path");
-       if(shader_path != "")
-       {
+       if (!shader_path.empty()) {
                std::string testpath = shader_path + DIR_DELIM + combined;
                if(fs::PathExists(testpath))
                        fullpath = testpath;
                std::string testpath = shader_path + DIR_DELIM + combined;
                if(fs::PathExists(testpath))
                        fullpath = testpath;
@@ -78,8 +77,7 @@ std::string getShaderPath(const std::string &name_of_shader,
        /*
                Check from default data directory
        */
        /*
                Check from default data directory
        */
-       if(fullpath == "")
-       {
+       if (fullpath.empty()) {
                std::string rel_path = std::string("client") + DIR_DELIM
                                + "shaders" + DIR_DELIM
                                + name_of_shader + DIR_DELIM
                std::string rel_path = std::string("client") + DIR_DELIM
                                + "shaders" + DIR_DELIM
                                + name_of_shader + DIR_DELIM
@@ -103,18 +101,16 @@ std::string getShaderPath(const std::string &name_of_shader,
 class SourceShaderCache
 {
 public:
 class SourceShaderCache
 {
 public:
-       void insert(const std::string &name_of_shader,
-                       const std::string &filename,
-                       const std::string &program,
-                       bool prefer_local)
+       void insert(const std::string &name_of_shader, const std::string &filename,
+               const std::string &program, bool prefer_local)
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
                // Try to use local shader instead if asked to
                if(prefer_local){
                        std::string path = getShaderPath(name_of_shader, filename);
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
                // Try to use local shader instead if asked to
                if(prefer_local){
                        std::string path = getShaderPath(name_of_shader, filename);
-                       if(path != ""){
+                       if(!path.empty()){
                                std::string p = readFile(path);
                                std::string p = readFile(path);
-                               if(p != ""){
+                               if (!p.empty()) {
                                        m_programs[combined] = p;
                                        return;
                                }
                                        m_programs[combined] = p;
                                        return;
                                }
@@ -122,42 +118,43 @@ class SourceShaderCache
                }
                m_programs[combined] = program;
        }
                }
                m_programs[combined] = program;
        }
+
        std::string get(const std::string &name_of_shader,
        std::string get(const std::string &name_of_shader,
-                       const std::string &filename)
+               const std::string &filename)
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
-               std::map<std::string, std::string>::iterator n;
-               n = m_programs.find(combined);
-               if(n != m_programs.end())
+               StringMap::iterator n = m_programs.find(combined);
+               if (n != m_programs.end())
                        return n->second;
                return "";
        }
                        return n->second;
                return "";
        }
+
        // Primarily fetches from cache, secondarily tries to read from filesystem
        std::string getOrLoad(const std::string &name_of_shader,
        // Primarily fetches from cache, secondarily tries to read from filesystem
        std::string getOrLoad(const std::string &name_of_shader,
-                       const std::string &filename)
+               const std::string &filename)
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
        {
                std::string combined = name_of_shader + DIR_DELIM + filename;
-               std::map<std::string, std::string>::iterator n;
-               n = m_programs.find(combined);
-               if(n != m_programs.end())
+               StringMap::iterator n = m_programs.find(combined);
+               if (n != m_programs.end())
                        return n->second;
                std::string path = getShaderPath(name_of_shader, filename);
                        return n->second;
                std::string path = getShaderPath(name_of_shader, filename);
-               if(path == ""){
-                       infostream<<"SourceShaderCache::getOrLoad(): No path found for \""
-                                       <<combined<<"\""<<std::endl;
+               if (path.empty()) {
+                       infostream << "SourceShaderCache::getOrLoad(): No path found for \""
+                               << combined << "\"" << std::endl;
                        return "";
                }
                        return "";
                }
-               infostream<<"SourceShaderCache::getOrLoad(): Loading path \""<<path
-                               <<"\""<<std::endl;
+               infostream << "SourceShaderCache::getOrLoad(): Loading path \""
+                       << path << "\"" << std::endl;
                std::string p = readFile(path);
                std::string p = readFile(path);
-               if(p != ""){
+               if (!p.empty()) {
                        m_programs[combined] = p;
                        return p;
                }
                return "";
        }
 private:
                        m_programs[combined] = p;
                        return p;
                }
                return "";
        }
 private:
-       std::map<std::string, std::string> m_programs;
+       StringMap m_programs;
+
        std::string readFile(const std::string &path)
        {
                std::ifstream is(path.c_str(), std::ios::binary);
        std::string readFile(const std::string &path)
        {
                std::ifstream is(path.c_str(), std::ios::binary);
@@ -169,106 +166,100 @@ class SourceShaderCache
        }
 };
 
        }
 };
 
+
 /*
        ShaderCallback: Sets constants that can be used in shaders
 */
 
 /*
        ShaderCallback: Sets constants that can be used in shaders
 */
 
-class IShaderConstantSetterRegistry
-{
-public:
-       virtual ~IShaderConstantSetterRegistry(){};
-       virtual void onSetConstants(video::IMaterialRendererServices *services,
-                       bool is_highlevel, const std::string &name) = 0;
-};
-
 class ShaderCallback : public video::IShaderConstantSetCallBack
 {
 class ShaderCallback : public video::IShaderConstantSetCallBack
 {
-       IShaderConstantSetterRegistry *m_scsr;
-       std::string m_name;
+       std::vector<IShaderConstantSetter*> m_setters;
 
 public:
 
 public:
-       ShaderCallback(IShaderConstantSetterRegistry *scsr, const std::string &name):
-               m_scsr(scsr),
-               m_name(name)
-       {}
-       ~ShaderCallback() {}
+       ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
+       {
+               for (IShaderConstantSetterFactory *factory : factories)
+                       m_setters.push_back(factory->create());
+       }
+
+       ~ShaderCallback()
+       {
+               for (IShaderConstantSetter *setter : m_setters)
+                       delete setter;
+       }
 
        virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
        {
                video::IVideoDriver *driver = services->getVideoDriver();
 
        virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
        {
                video::IVideoDriver *driver = services->getVideoDriver();
-               assert(driver);
+               sanity_check(driver != NULL);
 
                bool is_highlevel = userData;
 
 
                bool is_highlevel = userData;
 
-               m_scsr->onSetConstants(services, is_highlevel, m_name);
+               for (IShaderConstantSetter *setter : m_setters)
+                       setter->onSetConstants(services, is_highlevel);
        }
 };
 
        }
 };
 
+
 /*
        MainShaderConstantSetter: Set basic constants required for almost everything
 */
 
 class MainShaderConstantSetter : public IShaderConstantSetter
 {
 /*
        MainShaderConstantSetter: Set basic constants required for almost everything
 */
 
 class MainShaderConstantSetter : public IShaderConstantSetter
 {
+       CachedVertexShaderSetting<float, 16> m_world_view_proj;
+       CachedVertexShaderSetting<float, 16> m_world;
+
 public:
 public:
-       MainShaderConstantSetter(IrrlichtDevice *device):
-               m_device(device)
+       MainShaderConstantSetter() :
+               m_world_view_proj("mWorldViewProj"),
+               m_world("mWorld")
        {}
        {}
-       ~MainShaderConstantSetter() {}
+       ~MainShaderConstantSetter() = default;
 
        virtual void onSetConstants(video::IMaterialRendererServices *services,
                        bool is_highlevel)
        {
                video::IVideoDriver *driver = services->getVideoDriver();
 
        virtual void onSetConstants(video::IMaterialRendererServices *services,
                        bool is_highlevel)
        {
                video::IVideoDriver *driver = services->getVideoDriver();
-               assert(driver);
-
-               // set inverted world matrix
-               core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
-               invWorld.makeInverse();
-               if(is_highlevel)
-                       services->setVertexShaderConstant("mInvWorld", invWorld.pointer(), 16);
-               else
-                       services->setVertexShaderConstant(invWorld.pointer(), 0, 4);
+               sanity_check(driver);
 
 
-               // set clip matrix
+               // Set clip matrix
                core::matrix4 worldViewProj;
                worldViewProj = driver->getTransform(video::ETS_PROJECTION);
                worldViewProj *= driver->getTransform(video::ETS_VIEW);
                worldViewProj *= driver->getTransform(video::ETS_WORLD);
                core::matrix4 worldViewProj;
                worldViewProj = driver->getTransform(video::ETS_PROJECTION);
                worldViewProj *= driver->getTransform(video::ETS_VIEW);
                worldViewProj *= driver->getTransform(video::ETS_WORLD);
-               if(is_highlevel)
-                       services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
+               if (is_highlevel)
+                       m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
                else
                else
-                       services->setVertexShaderConstant(worldViewProj.pointer(), 4, 4);
+                       services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
 
 
-               // set transposed world matrix
-               core::matrix4 transWorld = driver->getTransform(video::ETS_WORLD);
-               transWorld = transWorld.getTransposed();
-               if(is_highlevel)
-                       services->setVertexShaderConstant("mTransWorld", transWorld.pointer(), 16);
-               else
-                       services->setVertexShaderConstant(transWorld.pointer(), 8, 4);
-
-               // set world matrix
+               // Set world matrix
                core::matrix4 world = driver->getTransform(video::ETS_WORLD);
                core::matrix4 world = driver->getTransform(video::ETS_WORLD);
-               if(is_highlevel)
-                       services->setVertexShaderConstant("mWorld", world.pointer(), 16);
+               if (is_highlevel)
+                       m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
                else
                else
-                       services->setVertexShaderConstant(world.pointer(), 8, 4);
+                       services->setVertexShaderConstant(world.pointer(), 4, 4);
 
        }
 
        }
+};
 
 
-private:
-       IrrlichtDevice *m_device;
+
+class MainShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+public:
+       virtual IShaderConstantSetter* create()
+               { return new MainShaderConstantSetter(); }
 };
 
 };
 
+
 /*
        ShaderSource
 */
 
 /*
        ShaderSource
 */
 
-class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterRegistry
+class ShaderSource : public IWritableShaderSource
 {
 public:
 {
 public:
-       ShaderSource(IrrlichtDevice *device);
+       ShaderSource();
        ~ShaderSource();
 
        /*
        ~ShaderSource();
 
        /*
@@ -278,23 +269,23 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
 
                The id 0 points to a null shader. Its material is EMT_SOLID.
        */
 
                The id 0 points to a null shader. Its material is EMT_SOLID.
        */
-       u32 getShaderIdDirect(const std::string &name, 
+       u32 getShaderIdDirect(const std::string &name,
                const u8 material_type, const u8 drawtype);
 
        /*
                If shader specified by the name pointed by the id doesn't
                const u8 material_type, const u8 drawtype);
 
        /*
                If shader specified by the name pointed by the id doesn't
-               exist, create it, then return id. 
+               exist, create it, then return id.
 
                Can be called from any thread. If called from some other thread
                and not found in cache, the call is queued to the main thread
                for processing.
        */
 
                Can be called from any thread. If called from some other thread
                and not found in cache, the call is queued to the main thread
                for processing.
        */
-       
+
        u32 getShader(const std::string &name,
                const u8 material_type, const u8 drawtype);
        u32 getShader(const std::string &name,
                const u8 material_type, const u8 drawtype);
-       
+
        ShaderInfo getShaderInfo(u32 id);
        ShaderInfo getShaderInfo(u32 id);
-       
+
        // Processes queued shader requests from other threads.
        // Shall be called from the main thread.
        void processQueue();
        // Processes queued shader requests from other threads.
        // Shall be called from the main thread.
        void processQueue();
@@ -308,22 +299,15 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
        // Shall be called from the main thread.
        void rebuildShaders();
 
        // Shall be called from the main thread.
        void rebuildShaders();
 
-       void addGlobalConstantSetter(IShaderConstantSetter *setter)
+       void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
        {
        {
-               m_global_setters.push_back(setter);
+               m_setter_factories.push_back(setter);
        }
 
        }
 
-       void onSetConstants(video::IMaterialRendererServices *services,
-                       bool is_highlevel, const std::string &name);
-
 private:
 
        // The id of the thread that is allowed to use irrlicht directly
 private:
 
        // The id of the thread that is allowed to use irrlicht directly
-       threadid_t m_main_thread;
-       // The irrlicht device
-       IrrlichtDevice *m_device;
-       // The set-constants callback
-       ShaderCallback *m_shader_callback;
+       std::thread::id m_main_thread;
 
        // Cache of source shaders
        // This should be only accessed from the main thread
 
        // Cache of source shaders
        // This should be only accessed from the main thread
@@ -333,105 +317,95 @@ class ShaderSource : public IWritableShaderSource, public IShaderConstantSetterR
        // The first position contains a dummy shader.
        std::vector<ShaderInfo> m_shaderinfo_cache;
        // The former container is behind this mutex
        // The first position contains a dummy shader.
        std::vector<ShaderInfo> m_shaderinfo_cache;
        // The former container is behind this mutex
-       JMutex m_shaderinfo_cache_mutex;
+       std::mutex m_shaderinfo_cache_mutex;
 
        // Queued shader fetches (to be processed by the main thread)
        RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
 
 
        // Queued shader fetches (to be processed by the main thread)
        RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
 
-       // Global constant setters
-       // TODO: Delete these in the destructor
-       std::vector<IShaderConstantSetter*> m_global_setters;
+       // Global constant setter factories
+       std::vector<IShaderConstantSetterFactory *> m_setter_factories;
+
+       // Shader callbacks
+       std::vector<ShaderCallback *> m_callbacks;
 };
 
 };
 
-IWritableShaderSource* createShaderSource(IrrlichtDevice *device)
+IWritableShaderSource *createShaderSource()
 {
 {
-       return new ShaderSource(device);
+       return new ShaderSource();
 }
 
 /*
        Generate shader given the shader name.
 */
 }
 
 /*
        Generate shader given the shader name.
 */
-ShaderInfo generate_shader(std::string name,
-               u8 material_type, u8 drawtype,
-               IrrlichtDevice *device,
-               video::IShaderConstantSetCallBack *callback,
+ShaderInfo generate_shader(const std::string &name,
+               u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
+               const std::vector<IShaderConstantSetterFactory *> &setter_factories,
                SourceShaderCache *sourcecache);
 
 /*
        Load shader programs
 */
                SourceShaderCache *sourcecache);
 
 /*
        Load shader programs
 */
-void load_shaders(std::string name, SourceShaderCache *sourcecache,
+void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
                video::E_DRIVER_TYPE drivertype, bool enable_shaders,
                std::string &vertex_program, std::string &pixel_program,
                std::string &geometry_program, bool &is_highlevel);
 
                video::E_DRIVER_TYPE drivertype, bool enable_shaders,
                std::string &vertex_program, std::string &pixel_program,
                std::string &geometry_program, bool &is_highlevel);
 
-ShaderSource::ShaderSource(IrrlichtDevice *device):
-               m_device(device)
+ShaderSource::ShaderSource()
 {
 {
-       assert(m_device);
-
-       m_shader_callback = new ShaderCallback(this, "default");
-
-       m_main_thread = get_current_thread_id();
+       m_main_thread = std::this_thread::get_id();
 
        // Add a dummy ShaderInfo as the first index, named ""
 
        // Add a dummy ShaderInfo as the first index, named ""
-       m_shaderinfo_cache.push_back(ShaderInfo());
+       m_shaderinfo_cache.emplace_back();
 
        // Add main global constant setter
 
        // Add main global constant setter
-       addGlobalConstantSetter(new MainShaderConstantSetter(device));
+       addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
 }
 
 ShaderSource::~ShaderSource()
 {
 }
 
 ShaderSource::~ShaderSource()
 {
-       for (std::vector<IShaderConstantSetter*>::iterator iter = m_global_setters.begin();
-                       iter != m_global_setters.end(); iter++) {
-               delete *iter;
+       for (ShaderCallback *callback : m_callbacks) {
+               delete callback;
        }
        }
-       m_global_setters.clear();
-
-       if (m_shader_callback) {
-               m_shader_callback->drop();
-               m_shader_callback = NULL;
+       for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
+               delete setter_factorie;
        }
 }
 
        }
 }
 
-u32 ShaderSource::getShader(const std::string &name, 
+u32 ShaderSource::getShader(const std::string &name,
                const u8 material_type, const u8 drawtype)
 {
        /*
                Get shader
        */
 
                const u8 material_type, const u8 drawtype)
 {
        /*
                Get shader
        */
 
-       if(get_current_thread_id() == m_main_thread){
+       if (std::this_thread::get_id() == m_main_thread) {
                return getShaderIdDirect(name, material_type, drawtype);
                return getShaderIdDirect(name, material_type, drawtype);
-       } else {
-               /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
+       }
 
 
-               // We're gonna ask the result to be put into here
+       /*errorstream<<"getShader(): Queued: name=\""<<name<<"\""<<std::endl;*/
 
 
-               static ResultQueue<std::string, u32, u8, u8> result_queue;
+       // We're gonna ask the result to be put into here
 
 
-               // Throw a request in
-               m_get_shader_queue.add(name, 0, 0, &result_queue);
+       static ResultQueue<std::string, u32, u8, u8> result_queue;
 
 
-               /* infostream<<"Waiting for shader from main thread, name=\""
-                               <<name<<"\""<<std::endl;*/
+       // Throw a request in
+       m_get_shader_queue.add(name, 0, 0, &result_queue);
 
 
-               while(true) {
-                       GetResult<std::string, u32, u8, u8>
-                               result = result_queue.pop_frontNoEx();
+       /* infostream<<"Waiting for shader from main thread, name=\""
+                       <<name<<"\""<<std::endl;*/
 
 
-                       if (result.key == name) {
-                               return result.item;
-                       }
-                       else {
-                               errorstream << "Got shader with invalid name: " << result.key << std::endl;
-                       }
+       while(true) {
+               GetResult<std::string, u32, u8, u8>
+                       result = result_queue.pop_frontNoEx();
+
+               if (result.key == name) {
+                       return result.item;
                }
 
                }
 
+               errorstream << "Got shader with invalid name: " << result.key << std::endl;
        }
 
        }
 
-       infostream<<"getShader(): Failed"<<std::endl;
+       infostream << "getShader(): Failed" << std::endl;
 
        return 0;
 }
 
        return 0;
 }
@@ -439,13 +413,13 @@ u32 ShaderSource::getShader(const std::string &name,
 /*
        This method generates all the shaders
 */
 /*
        This method generates all the shaders
 */
-u32 ShaderSource::getShaderIdDirect(const std::string &name, 
+u32 ShaderSource::getShaderIdDirect(const std::string &name,
                const u8 material_type, const u8 drawtype)
 {
        //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
 
        // Empty name means shader 0
                const u8 material_type, const u8 drawtype)
 {
        //infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
 
        // Empty name means shader 0
-       if(name == ""){
+       if (name.empty()) {
                infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
                return 0;
        }
                infostream<<"getShaderIdDirect(): name is empty"<<std::endl;
                return 0;
        }
@@ -461,20 +435,20 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
        /*
                Calling only allowed from main thread
        */
        /*
                Calling only allowed from main thread
        */
-       if(get_current_thread_id() != m_main_thread){
+       if (std::this_thread::get_id() != m_main_thread) {
                errorstream<<"ShaderSource::getShaderIdDirect() "
                                "called not from main thread"<<std::endl;
                return 0;
        }
 
                errorstream<<"ShaderSource::getShaderIdDirect() "
                                "called not from main thread"<<std::endl;
                return 0;
        }
 
-       ShaderInfo info = generate_shader(name, material_type, drawtype, m_device,
-                       m_shader_callback, &m_sourcecache);
+       ShaderInfo info = generate_shader(name, material_type, drawtype,
+                       m_callbacks, m_setter_factories, &m_sourcecache);
 
        /*
                Add shader to caches (add dummy shaders too)
        */
 
 
        /*
                Add shader to caches (add dummy shaders too)
        */
 
-       JMutexAutoLock lock(m_shaderinfo_cache_mutex);
+       MutexAutoLock lock(m_shaderinfo_cache_mutex);
 
        u32 id = m_shaderinfo_cache.size();
        m_shaderinfo_cache.push_back(info);
 
        u32 id = m_shaderinfo_cache.size();
        m_shaderinfo_cache.push_back(info);
@@ -488,7 +462,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
 
 ShaderInfo ShaderSource::getShaderInfo(u32 id)
 {
 
 ShaderInfo ShaderSource::getShaderInfo(u32 id)
 {
-       JMutexAutoLock lock(m_shaderinfo_cache_mutex);
+       MutexAutoLock lock(m_shaderinfo_cache_mutex);
 
        if(id >= m_shaderinfo_cache.size())
                return ShaderInfo();
 
        if(id >= m_shaderinfo_cache.size())
                return ShaderInfo();
@@ -498,7 +472,7 @@ ShaderInfo ShaderSource::getShaderInfo(u32 id)
 
 void ShaderSource::processQueue()
 {
 
 void ShaderSource::processQueue()
 {
+
 
 }
 
 
 }
 
@@ -509,14 +483,14 @@ void ShaderSource::insertSourceShader(const std::string &name_of_shader,
                        "name_of_shader=\""<<name_of_shader<<"\", "
                        "filename=\""<<filename<<"\""<<std::endl;*/
 
                        "name_of_shader=\""<<name_of_shader<<"\", "
                        "filename=\""<<filename<<"\""<<std::endl;*/
 
-       assert(get_current_thread_id() == m_main_thread);
+       sanity_check(std::this_thread::get_id() == m_main_thread);
 
        m_sourcecache.insert(name_of_shader, filename, program, true);
 }
 
 void ShaderSource::rebuildShaders()
 {
 
        m_sourcecache.insert(name_of_shader, filename, program, true);
 }
 
 void ShaderSource::rebuildShaders()
 {
-       JMutexAutoLock lock(m_shaderinfo_cache_mutex);
+       MutexAutoLock lock(m_shaderinfo_cache_mutex);
 
        /*// Oh well... just clear everything, they'll load sometime.
        m_shaderinfo_cache.clear();
 
        /*// Oh well... just clear everything, they'll load sometime.
        m_shaderinfo_cache.clear();
@@ -529,26 +503,20 @@ void ShaderSource::rebuildShaders()
        */
 
        // Recreate shaders
        */
 
        // Recreate shaders
-       for(u32 i=0; i<m_shaderinfo_cache.size(); i++){
-               ShaderInfo *info = &m_shaderinfo_cache[i];
-               if(info->name != ""){
+       for (ShaderInfo &i : m_shaderinfo_cache) {
+               ShaderInfo *info = &i;
+               if (!info->name.empty()) {
                        *info = generate_shader(info->name, info->material_type,
                        *info = generate_shader(info->name, info->material_type,
-                                       info->drawtype, m_device, m_shader_callback, &m_sourcecache);
+                                       info->drawtype, m_callbacks,
+                                       m_setter_factories, &m_sourcecache);
                }
        }
 }
 
                }
        }
 }
 
-void ShaderSource::onSetConstants(video::IMaterialRendererServices *services,
-               bool is_highlevel, const std::string &name)
-{
-       for(u32 i=0; i<m_global_setters.size(); i++){
-               IShaderConstantSetter *setter = m_global_setters[i];
-               setter->onSetConstants(services, is_highlevel);
-       }
-}
 
 
-ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
-               IrrlichtDevice *device, video::IShaderConstantSetCallBack *callback,
+ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
+               std::vector<ShaderCallback *> &callbacks,
+               const std::vector<IShaderConstantSetterFactory *> &setter_factories,
                SourceShaderCache *sourcecache)
 {
        ShaderInfo shaderinfo;
                SourceShaderCache *sourcecache)
 {
        ShaderInfo shaderinfo;
@@ -556,33 +524,27 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
        shaderinfo.material_type = material_type;
        shaderinfo.drawtype = drawtype;
        shaderinfo.material = video::EMT_SOLID;
        shaderinfo.material_type = material_type;
        shaderinfo.drawtype = drawtype;
        shaderinfo.material = video::EMT_SOLID;
-       switch(material_type){
-               case TILE_MATERIAL_BASIC:
-                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
-                       break;
-               case TILE_MATERIAL_ALPHA:
-                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
-                       break;
-               case TILE_MATERIAL_LIQUID_TRANSPARENT:
-                       shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
-                       break;
-               case TILE_MATERIAL_LIQUID_OPAQUE:
-                       shaderinfo.base_material = video::EMT_SOLID;
-                       break;
-               case TILE_MATERIAL_WAVING_LEAVES:
-                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
-                       break;
-               case TILE_MATERIAL_WAVING_PLANTS:
-                       shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+       switch (material_type) {
+       case TILE_MATERIAL_OPAQUE:
+       case TILE_MATERIAL_LIQUID_OPAQUE:
+               shaderinfo.base_material = video::EMT_SOLID;
+               break;
+       case TILE_MATERIAL_ALPHA:
+       case TILE_MATERIAL_LIQUID_TRANSPARENT:
+               shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+               break;
+       case TILE_MATERIAL_BASIC:
+       case TILE_MATERIAL_WAVING_LEAVES:
+       case TILE_MATERIAL_WAVING_PLANTS:
+               shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
                break;
        }
                break;
        }
-       
+
        bool enable_shaders = g_settings->getBool("enable_shaders");
        bool enable_shaders = g_settings->getBool("enable_shaders");
-       if(!enable_shaders)
+       if (!enable_shaders)
                return shaderinfo;
 
                return shaderinfo;
 
-       video::IVideoDriver* driver = device->getVideoDriver();
-       assert(driver);
+       video::IVideoDriver *driver = RenderingEngine::get_video_driver();
 
        video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
        if(!gpu){
 
        video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
        if(!gpu){
@@ -603,7 +565,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                        enable_shaders, vertex_program, pixel_program,
                        geometry_program, is_highlevel);
        // Check hardware/driver support
                        enable_shaders, vertex_program, pixel_program,
                        geometry_program, is_highlevel);
        // Check hardware/driver support
-       if(vertex_program != "" &&
+       if (!vertex_program.empty() &&
                        !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
                        !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
                infostream<<"generate_shader(): vertex shaders disabled "
                        !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
                        !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
                infostream<<"generate_shader(): vertex shaders disabled "
@@ -611,7 +573,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                                <<std::endl;
                vertex_program = "";
        }
                                <<std::endl;
                vertex_program = "";
        }
-       if(pixel_program != "" &&
+       if (!pixel_program.empty() &&
                        !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
                        !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
                infostream<<"generate_shader(): pixel shaders disabled "
                        !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
                        !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
                infostream<<"generate_shader(): pixel shaders disabled "
@@ -619,7 +581,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                                <<std::endl;
                pixel_program = "";
        }
                                <<std::endl;
                pixel_program = "";
        }
-       if(geometry_program != "" &&
+       if (!geometry_program.empty() &&
                        !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
                infostream<<"generate_shader(): geometry shaders disabled "
                                "because of missing driver/hardware support."
                        !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
                infostream<<"generate_shader(): geometry shaders disabled "
                                "because of missing driver/hardware support."
@@ -628,7 +590,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
        }
 
        // If no shaders are used, don't make a separate material type
        }
 
        // If no shaders are used, don't make a separate material type
-       if(vertex_program == "" && pixel_program == "" && geometry_program == "")
+       if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
                return shaderinfo;
 
        // Create shaders header
                return shaderinfo;
 
        // Create shaders header
@@ -648,9 +610,12 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                "NDT_FENCELIKE",
                "NDT_RAILLIKE",
                "NDT_NODEBOX",
                "NDT_FENCELIKE",
                "NDT_RAILLIKE",
                "NDT_NODEBOX",
-               "NDT_GLASSLIKE_FRAMED"
+               "NDT_GLASSLIKE_FRAMED",
+               "NDT_FIRELIKE",
+               "NDT_GLASSLIKE_FRAMED_OPTIONAL",
+               "NDT_PLANTLIKE_ROOTED",
        };
        };
-       
+
        for (int i = 0; i < 14; i++){
                shaders_header += "#define ";
                shaders_header += drawTypes[i];
        for (int i = 0; i < 14; i++){
                shaders_header += "#define ";
                shaders_header += drawTypes[i];
@@ -665,10 +630,11 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                "TILE_MATERIAL_LIQUID_TRANSPARENT",
                "TILE_MATERIAL_LIQUID_OPAQUE",
                "TILE_MATERIAL_WAVING_LEAVES",
                "TILE_MATERIAL_LIQUID_TRANSPARENT",
                "TILE_MATERIAL_LIQUID_OPAQUE",
                "TILE_MATERIAL_WAVING_LEAVES",
-               "TILE_MATERIAL_WAVING_PLANTS"
+               "TILE_MATERIAL_WAVING_PLANTS",
+               "TILE_MATERIAL_OPAQUE"
        };
 
        };
 
-       for (int i = 0; i < 6; i++){
+       for (int i = 0; i < 7; i++){
                shaders_header += "#define ";
                shaders_header += materialTypes[i];
                shaders_header += " ";
                shaders_header += "#define ";
                shaders_header += materialTypes[i];
                shaders_header += " ";
@@ -683,47 +649,62 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
        shaders_header += itos(drawtype);
        shaders_header += "\n";
 
        shaders_header += itos(drawtype);
        shaders_header += "\n";
 
-       if (g_settings->getBool("generate_normalmaps")){
-               shaders_header += "#define GENERATE_NORMALMAPS\n";
-               shaders_header += "#define NORMALMAPS_STRENGTH ";
-               shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
-               shaders_header += "\n";
-               float sample_step;
-               int smooth = (int)g_settings->getFloat("normalmaps_smooth");
-               switch (smooth){
-               case 0:
-                       sample_step = 0.0078125; // 1.0 / 128.0
-                       break;
-               case 1:
-                       sample_step = 0.00390625; // 1.0 / 256.0
-                       break;
-               case 2:
-                       sample_step = 0.001953125; // 1.0 / 512.0
-                       break;
-               default:
-                       sample_step = 0.0078125;
-                       break;
-               }
-               shaders_header += "#define SAMPLE_STEP ";
-               shaders_header += ftos(sample_step);
-               shaders_header += "\n";
+       if (g_settings->getBool("generate_normalmaps")) {
+               shaders_header += "#define GENERATE_NORMALMAPS 1\n";
+       } else {
+               shaders_header += "#define GENERATE_NORMALMAPS 0\n";
+       }
+       shaders_header += "#define NORMALMAPS_STRENGTH ";
+       shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
+       shaders_header += "\n";
+       float sample_step;
+       int smooth = (int)g_settings->getFloat("normalmaps_smooth");
+       switch (smooth){
+       case 0:
+               sample_step = 0.0078125; // 1.0 / 128.0
+               break;
+       case 1:
+               sample_step = 0.00390625; // 1.0 / 256.0
+               break;
+       case 2:
+               sample_step = 0.001953125; // 1.0 / 512.0
+               break;
+       default:
+               sample_step = 0.0078125;
+               break;
        }
        }
+       shaders_header += "#define SAMPLE_STEP ";
+       shaders_header += ftos(sample_step);
+       shaders_header += "\n";
 
        if (g_settings->getBool("enable_bumpmapping"))
                shaders_header += "#define ENABLE_BUMPMAPPING\n";
 
        if (g_settings->getBool("enable_parallax_occlusion")){
 
        if (g_settings->getBool("enable_bumpmapping"))
                shaders_header += "#define ENABLE_BUMPMAPPING\n";
 
        if (g_settings->getBool("enable_parallax_occlusion")){
+               int mode = g_settings->getFloat("parallax_occlusion_mode");
+               float scale = g_settings->getFloat("parallax_occlusion_scale");
+               float bias = g_settings->getFloat("parallax_occlusion_bias");
+               int iterations = g_settings->getFloat("parallax_occlusion_iterations");
                shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
                shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
+               shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
+               shaders_header += itos(mode);
+               shaders_header += "\n";
                shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
                shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
-               shaders_header += ftos(g_settings->getFloat("parallax_occlusion_scale"));
+               shaders_header += ftos(scale);
                shaders_header += "\n";
                shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
                shaders_header += "\n";
                shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
-               shaders_header += ftos(g_settings->getFloat("parallax_occlusion_bias"));
+               shaders_header += ftos(bias);
+               shaders_header += "\n";
+               shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
+               shaders_header += itos(iterations);
                shaders_header += "\n";
        }
 
                shaders_header += "\n";
        }
 
+       shaders_header += "#define USE_NORMALMAPS ";
        if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
        if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
-               shaders_header += "#define USE_NORMALMAPS\n";
+               shaders_header += "1\n";
+       else
+               shaders_header += "0\n";
 
        if (g_settings->getBool("enable_waving_water")){
                shaders_header += "#define ENABLE_WAVING_WATER 1\n";
 
        if (g_settings->getBool("enable_waving_water")){
                shaders_header += "#define ENABLE_WAVING_WATER 1\n";
@@ -743,32 +724,39 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
        shaders_header += "#define ENABLE_WAVING_LEAVES ";
        if (g_settings->getBool("enable_waving_leaves"))
                shaders_header += "1\n";
        shaders_header += "#define ENABLE_WAVING_LEAVES ";
        if (g_settings->getBool("enable_waving_leaves"))
                shaders_header += "1\n";
-       else    
+       else
                shaders_header += "0\n";
 
                shaders_header += "0\n";
 
-       shaders_header += "#define ENABLE_WAVING_PLANTS ";              
+       shaders_header += "#define ENABLE_WAVING_PLANTS ";
        if (g_settings->getBool("enable_waving_plants"))
                shaders_header += "1\n";
        else
                shaders_header += "0\n";
 
        if (g_settings->getBool("enable_waving_plants"))
                shaders_header += "1\n";
        else
                shaders_header += "0\n";
 
-       if(pixel_program != "")
-               pixel_program = shaders_header + pixel_program;
-       if(vertex_program != "")
-               vertex_program = shaders_header + vertex_program;
-       if(geometry_program != "")
-               geometry_program = shaders_header + geometry_program;
+       if (g_settings->getBool("tone_mapping"))
+               shaders_header += "#define ENABLE_TONE_MAPPING\n";
+
+       shaders_header += "#define FOG_START ";
+       shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
+       shaders_header += "\n";
 
        // Call addHighLevelShaderMaterial() or addShaderMaterial()
        const c8* vertex_program_ptr = 0;
        const c8* pixel_program_ptr = 0;
        const c8* geometry_program_ptr = 0;
 
        // Call addHighLevelShaderMaterial() or addShaderMaterial()
        const c8* vertex_program_ptr = 0;
        const c8* pixel_program_ptr = 0;
        const c8* geometry_program_ptr = 0;
-       if(vertex_program != "")
+       if (!vertex_program.empty()) {
+               vertex_program = shaders_header + vertex_program;
                vertex_program_ptr = vertex_program.c_str();
                vertex_program_ptr = vertex_program.c_str();
-       if(pixel_program != "")
+       }
+       if (!pixel_program.empty()) {
+               pixel_program = shaders_header + pixel_program;
                pixel_program_ptr = pixel_program.c_str();
                pixel_program_ptr = pixel_program.c_str();
-       if(geometry_program != "")
+       }
+       if (!geometry_program.empty()) {
+               geometry_program = shaders_header + geometry_program;
                geometry_program_ptr = geometry_program.c_str();
                geometry_program_ptr = geometry_program.c_str();
+       }
+       ShaderCallback *cb = new ShaderCallback(setter_factories);
        s32 shadermat = -1;
        if(is_highlevel){
                infostream<<"Compiling high level shaders for "<<name<<std::endl;
        s32 shadermat = -1;
        if(is_highlevel){
                infostream<<"Compiling high level shaders for "<<name<<std::endl;
@@ -778,14 +766,14 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                        video::EVST_VS_1_1,   // Vertex shader version
                        pixel_program_ptr,    // Pixel shader program
                        "pixelMain",          // Pixel shader entry point
                        video::EVST_VS_1_1,   // Vertex shader version
                        pixel_program_ptr,    // Pixel shader program
                        "pixelMain",          // Pixel shader entry point
-                       video::EPST_PS_1_1,   // Pixel shader version
+                       video::EPST_PS_1_2,   // Pixel shader version
                        geometry_program_ptr, // Geometry shader program
                        "geometryMain",       // Geometry shader entry point
                        video::EGST_GS_4_0,   // Geometry shader version
                        scene::EPT_TRIANGLES,      // Geometry shader input
                        scene::EPT_TRIANGLE_STRIP, // Geometry shader output
                        0,                         // Support maximum number of vertices
                        geometry_program_ptr, // Geometry shader program
                        "geometryMain",       // Geometry shader entry point
                        video::EGST_GS_4_0,   // Geometry shader version
                        scene::EPT_TRIANGLES,      // Geometry shader input
                        scene::EPT_TRIANGLE_STRIP, // Geometry shader output
                        0,                         // Support maximum number of vertices
-                       callback,                  // Set-constant callback
+                       cb, // Set-constant callback
                        shaderinfo.base_material,  // Base material
                        1                          // Userdata passed to callback
                        );
                        shaderinfo.base_material,  // Base material
                        1                          // Userdata passed to callback
                        );
@@ -794,6 +782,10 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                                        "failed to generate \""<<name<<"\", "
                                        "addHighLevelShaderMaterial failed."
                                        <<std::endl;
                                        "failed to generate \""<<name<<"\", "
                                        "addHighLevelShaderMaterial failed."
                                        <<std::endl;
+                       dumpShaderProgram(warningstream, "Vertex", vertex_program);
+                       dumpShaderProgram(warningstream, "Pixel", pixel_program);
+                       dumpShaderProgram(warningstream, "Geometry", geometry_program);
+                       delete cb;
                        return shaderinfo;
                }
        }
                        return shaderinfo;
                }
        }
@@ -802,7 +794,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                shadermat = gpu->addShaderMaterial(
                        vertex_program_ptr,   // Vertex shader program
                        pixel_program_ptr,    // Pixel shader program
                shadermat = gpu->addShaderMaterial(
                        vertex_program_ptr,   // Vertex shader program
                        pixel_program_ptr,    // Pixel shader program
-                       callback,             // Set-constant callback
+                       cb, // Set-constant callback
                        shaderinfo.base_material,  // Base material
                        0                     // Userdata passed to callback
                        );
                        shaderinfo.base_material,  // Base material
                        0                     // Userdata passed to callback
                        );
@@ -812,9 +804,13 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
                                        "failed to generate \""<<name<<"\", "
                                        "addShaderMaterial failed."
                                        <<std::endl;
                                        "failed to generate \""<<name<<"\", "
                                        "addShaderMaterial failed."
                                        <<std::endl;
+                       dumpShaderProgram(warningstream, "Vertex", vertex_program);
+                       dumpShaderProgram(warningstream,"Pixel", pixel_program);
+                       delete cb;
                        return shaderinfo;
                }
        }
                        return shaderinfo;
                }
        }
+       callbacks.push_back(cb);
 
        // HACK, TODO: investigate this better
        // Grab the material renderer once more so minetest doesn't crash on exit
 
        // HACK, TODO: investigate this better
        // Grab the material renderer once more so minetest doesn't crash on exit
@@ -825,7 +821,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
        return shaderinfo;
 }
 
        return shaderinfo;
 }
 
-void load_shaders(std::string name, SourceShaderCache *sourcecache,
+void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
                video::E_DRIVER_TYPE drivertype, bool enable_shaders,
                std::string &vertex_program, std::string &pixel_program,
                std::string &geometry_program, bool &is_highlevel)
                video::E_DRIVER_TYPE drivertype, bool enable_shaders,
                std::string &vertex_program, std::string &pixel_program,
                std::string &geometry_program, bool &is_highlevel)
@@ -850,10 +846,28 @@ void load_shaders(std::string name, SourceShaderCache *sourcecache,
                        pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
                        geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
                }
                        pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
                        geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
                }
-               if(vertex_program != "" || pixel_program != "" || geometry_program != ""){
+               if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
                        is_highlevel = true;
                        return;
                }
        }
 
 }
                        is_highlevel = true;
                        return;
                }
        }
 
 }
+
+void dumpShaderProgram(std::ostream &output_stream,
+               const std::string &program_type, const std::string &program)
+{
+       output_stream << program_type << " shader program:" << std::endl <<
+               "----------------------------------" << std::endl;
+       size_t pos = 0;
+       size_t prev = 0;
+       s16 line = 1;
+       while ((pos = program.find('\n', prev)) != std::string::npos) {
+               output_stream << line++ << ": "<< program.substr(prev, pos - prev) <<
+                       std::endl;
+               prev = pos + 1;
+       }
+       output_stream << line << ": " << program.substr(prev) << std::endl <<
+               "End of " << program_type << " shader program." << std::endl <<
+               " " << std::endl;
+}