Merge branch 'master' into blender2.8
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 14 Feb 2018 20:49:13 +0000 (21:49 +0100)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 14 Feb 2018 20:49:13 +0000 (21:49 +0100)
1  2 
source/blender/gpu/GPU_material.h
source/blender/gpu/intern/gpu_draw.c
source/blender/gpu/intern/gpu_material.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/nodes/shader/nodes/node_shader_particle_info.c
source/blender/render/extern/include/RE_shader_ext.h

index 698f3ada2a346f8eed64fc1eaf5f591448d2cb56,e229afd3323b78b39281dbcb57b4d718b148db6b..e2f40ff5c54763027655a6718bee3f52427b9f97
@@@ -43,33 -43,30 +43,33 @@@ extern "C" 
  
  struct Image;
  struct ImageUser;
 +struct ListBase;
  struct Material;
  struct Object;
 -struct Image;
  struct Scene;
 -struct SceneRenderLayer;
  struct GPUVertexAttribs;
  struct GPUNode;
  struct GPUNodeLink;
  struct GPUNodeStack;
  struct GPUMaterial;
  struct GPUTexture;
 +struct GPUUniformBuffer;
  struct GPULamp;
  struct PreviewImage;
  struct World;
 +struct bNode;
 +struct bNodeTree;
  
  typedef struct GPUNode GPUNode;
  typedef struct GPUNodeLink GPUNodeLink;
  typedef struct GPUMaterial GPUMaterial;
 -typedef struct GPULamp GPULamp;
 +
  typedef struct GPUParticleInfo GPUParticleInfo;
  
  /* Functions to create GPU Materials nodes */
  
  typedef enum GPUType {
 +      /* Keep in sync with GPU_DATATYPE_STR */
        /* The value indicates the number of elements in each type */
        GPU_NONE = 0,
        GPU_FLOAT = 1,
        GPU_MAT3 = 9,
        GPU_MAT4 = 16,
  
 +      /* Values not in GPU_DATATYPE_STR */
        GPU_TEX2D = 1002,
 -      GPU_SHADOW2D = 1003,
 -      GPU_TEXCUBE = 1004,
 +      GPU_TEX3D = 1003,
 +      GPU_SHADOW2D = 1004,
 +      GPU_TEXCUBE = 1005,
 +
 +      /* GLSL Struct types */
 +      GPU_CLOSURE = 1006,
 +
 +      /* Opengl Attributes */
        GPU_ATTRIB = 3001
  } GPUType;
  
@@@ -108,9 -98,7 +108,9 @@@ typedef enum GPUBuiltin 
        GPU_PARTICLE_ANG_VELOCITY = (1 << 12),
        GPU_LOC_TO_VIEW_MATRIX =    (1 << 13),
        GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14),
 -      GPU_OBJECT_INFO =           (1 << 15)
 +      GPU_OBJECT_INFO =           (1 << 15),
 +      GPU_VOLUME_DENSITY =        (1 << 16),
 +      GPU_VOLUME_FLAME =          (1 << 17)
  } GPUBuiltin;
  
  typedef enum GPUOpenGLBuiltin {
@@@ -153,7 -141,6 +153,7 @@@ typedef struct GPUNodeStack 
  #define GPU_DYNAMIC_GROUP_MIST     0x00050000
  #define GPU_DYNAMIC_GROUP_WORLD    0x00060000
  #define GPU_DYNAMIC_GROUP_MAT      0x00070000
 +#define GPU_DYNAMIC_UBO            0x00080000
  
  typedef enum GPUDynamicType {
  
  GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
  GPUNodeLink *GPU_uniform(float *num);
  GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data);
 +GPUNodeLink *GPU_uniform_buffer(float *num, GPUType gputype);
  GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data);
  GPUNodeLink *GPU_cube_map(struct Image *ima, struct ImageUser *iuser, bool is_data);
  GPUNodeLink *GPU_image_preview(struct PreviewImage *prv);
@@@ -224,36 -210,26 +224,36 @@@ GPUNodeLink *GPU_opengl_builtin(GPUOpen
  void GPU_node_link_set_type(GPUNodeLink *link, GPUType type);
  
  bool GPU_link(GPUMaterial *mat, const char *name, ...);
 -bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...);
 +bool GPU_stack_link(GPUMaterial *mat, struct bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...);
 +GPUNodeLink *GPU_uniformbuffer_link_out(
 +        struct GPUMaterial *mat, struct bNode *node,
 +        struct GPUNodeStack *stack, const int index);
  
  void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link);
  void GPU_material_enable_alpha(GPUMaterial *material);
  GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
  GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
  
 +void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness);
 +struct GPUUniformBuffer *GPU_material_sss_profile_get(
 +        GPUMaterial *material, int sample_ct, struct GPUTexture **tex_profile);
 +
  /* High level functions to create and use GPU materials */
  GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo);
 -
 +GPUMaterial *GPU_material_from_nodetree_find(
 +        struct ListBase *gpumaterials, const void *engine_type, int options);
 +GPUMaterial *GPU_material_from_nodetree(
 +        struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, int options,
 +        const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines);
  GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
  GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv);
  void GPU_material_free(struct ListBase *gpumaterial);
  
  void GPU_materials_free(void);
  
 -bool GPU_lamp_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
  void GPU_material_bind(
          GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
 -        float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
 +        float viewmat[4][4], float viewinv[4][4], float cameraborder[4]);
  void GPU_material_bind_uniforms(
          GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4],
          float autobumpscale, GPUParticleInfo *pi, float object_info[3]);
@@@ -261,11 -237,6 +261,11 @@@ void GPU_material_unbind(GPUMaterial *m
  bool GPU_material_bound(GPUMaterial *material);
  struct Scene *GPU_material_scene(GPUMaterial *material);
  GPUMatType GPU_Material_get_type(GPUMaterial *material);
 +struct GPUPass *GPU_material_get_pass(GPUMaterial *material);
 +
 +struct GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material);
 +void GPU_material_create_uniform_buffer(GPUMaterial *material, struct ListBase *inputs);
 +void GPU_material_uniform_buffer_tag_dirty(struct ListBase *gpumaterials);
  
  void GPU_material_vertex_attributes(GPUMaterial *material,
        struct GPUVertexAttribs *attrib);
  bool GPU_material_do_color_management(GPUMaterial *mat);
  bool GPU_material_use_new_shading_nodes(GPUMaterial *mat);
  bool GPU_material_use_world_space_shading(GPUMaterial *mat);
 +bool GPU_material_use_domain_surface(GPUMaterial *mat);
 +bool GPU_material_use_domain_volume(GPUMaterial *mat);
  
  /* Exported shading */
  
@@@ -343,8 -312,26 +343,8 @@@ GPUShaderExport *GPU_shader_export(stru
  void GPU_free_shader_export(GPUShaderExport *shader);
  
  /* Lamps */
 -
 -GPULamp *GPU_lamp_from_blender(struct Scene *scene, struct Object *ob, struct Object *par);
 -void GPU_lamp_free(struct Object *ob);
 -
 -bool GPU_lamp_has_shadow_buffer(GPULamp *lamp);
 -void GPU_lamp_update_buffer_mats(GPULamp *lamp);
 -void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4]);
 -void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp);
 -int GPU_lamp_shadow_buffer_type(GPULamp *lamp);
 -int GPU_lamp_shadow_bind_code(GPULamp *lamp);
 -float *GPU_lamp_dynpersmat(GPULamp *lamp);
 -
 -void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]);
 -void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy);
 -void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2,
 -                              float coeff_const, float coeff_lin, float coeff_quad);
 -void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend);
 -int GPU_lamp_shadow_layer(GPULamp *lamp);
  GPUNodeLink *GPU_lamp_get_data(
 -        GPUMaterial *mat, GPULamp *lamp,
 +        GPUMaterial *mat, struct GPULamp *lamp,
          GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy);
  
  /* World */
@@@ -357,10 -344,9 +357,9 @@@ void GPU_zenith_update_color(float colo
  struct GPUParticleInfo
  {
        float scalprops[4];
-       float location[3];
+       float location[4];
        float velocity[3];
        float angular_velocity[3];
-       int random_id;
  };
  
  #ifdef WITH_OPENSUBDIV
index ca569d68dee13a2d8e063577bf414a18c911dbc5,61d57dee092c5eec89a37f718f4044fc35cfe2d4..2f52212cb220403bf73d3fdd9f7b68ebdea09961
@@@ -38,6 -38,8 +38,6 @@@
  
  #include <string.h>
  
 -#include "GPU_glew.h"
 -
  #include "BLI_blenlib.h"
  #include "BLI_hash.h"
  #include "BLI_linklist.h"
@@@ -79,7 -81,6 +79,7 @@@
  #include "GPU_draw.h"
  #include "GPU_extensions.h"
  #include "GPU_material.h"
 +#include "GPU_matrix.h"
  #include "GPU_shader.h"
  #include "GPU_texture.h"
  
@@@ -108,27 -109,23 +108,27 @@@ static void gpu_mcol(unsigned int ucol
  }
  
  void GPU_render_text(
 -        MTexPoly *mtexpoly, int mode,
 -        const char *textstr, int textlen, unsigned int *col,
 +        int mode, const char *textstr, int textlen, unsigned int *col,
          const float *v_quad[4], const float *uv_quad[4],
          int glattrib)
  {
 -      if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) {
 +      /* XXX, 2.8 removes texface */
 +#if 0
 +      Image *ima = mtexpoly->tpage;
 +#else
 +      Image *ima = NULL;
 +#endif
 +      if ((mode & GEMAT_TEXT) && (textlen > 0) && ima) {
                const float *v1 = v_quad[0];
                const float *v2 = v_quad[1];
                const float *v3 = v_quad[2];
                const float *v4 = v_quad[3];
 -              Image *ima = (Image *)mtexpoly->tpage;
                const size_t textlen_st = textlen;
                float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
 -              
 +
                /* multiline */
                float line_start = 0.0f, line_height;
 -              
 +
                if (v4)
                        line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]);
                else
                line_height *= 1.2f; /* could be an option? */
                /* end multiline */
  
 -              
 +
                /* color has been set */
 -              if (mtexpoly->mode & TF_OBCOL)
 -                      col = NULL;
 -              else if (!col)
 +              if (!col)
                        glColor3f(1.0f, 1.0f, 1.0f);
  
 -              glPushMatrix();
 -              
 +              gpuPushMatrix();
 +
                /* get the tab width */
                ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima);
                matrixGlyph(first_ibuf, ' ', &centerx, &centery,
 -                      &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
 -              
 +                  &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
 +
                float advance_tab = advance * 4; /* tab width could also be an option */
 -              
 -              
 +
 +
                for (size_t index = 0; index < textlen_st; ) {
                        unsigned int character;
                        float uv[4][2];
  
                        /* lets calculate offset stuff */
                        character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index);
 -                      
 +
                        if (character == '\n') {
 -                              glTranslatef(line_start, -line_height, 0.0f);
 +                              gpuTranslate2f(line_start, -line_height);
                                line_start = 0.0f;
                                continue;
                        }
                        else if (character == '\t') {
 -                              glTranslatef(advance_tab, 0.0f, 0.0f);
 +                              gpuTranslate2f(advance_tab, 0.0f);
                                line_start -= advance_tab; /* so we can go back to the start of the line */
                                continue;
 -                              
 +
                        }
                        else if (character > USHRT_MAX) {
                                /* not much we can do here bmfonts take ushort */
                                character = '?';
                        }
 -                      
 +
                        /* space starts at offset 1 */
                        /* character = character - ' ' + 1; */
                        matrixGlyph(first_ibuf, character, & centerx, &centery,
 -                              &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
 +                          &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
  
                        uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx;
                        uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy;
                        uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy;
                        uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx;
                        uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy;
 -                      
 +
                        glBegin(GL_POLYGON);
                        if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]);
                        else glTexCoord2fv(uv[0]);
                        if (col) gpu_mcol(col[0]);
                        glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
 -                      
 +
                        if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]);
                        else glTexCoord2fv(uv[1]);
                        if (col) gpu_mcol(col[1]);
                        }
                        glEnd();
  
 -                      glTranslatef(advance, 0.0f, 0.0f);
 +                      gpuTranslate2f(advance, 0.0f);
                        line_start -= advance; /* so we can go back to the start of the line */
                }
 -              glPopMatrix();
 +              gpuPopMatrix();
  
                BKE_image_release_ibuf(ima, first_ibuf, NULL);
        }
  }
  
  /* Checking powers of two for images since OpenGL ES requires it */
 -
 +#ifdef WITH_DDS
  static bool is_power_of_2_resolution(int w, int h)
  {
        return is_power_of_2_i(w) && is_power_of_2_i(h);
  }
 +#endif
  
  static bool is_over_resolution_limit(GLenum textarget, int w, int h)
  {
        int size = (textarget == GL_TEXTURE_2D) ?
                GPU_max_texture_size() : GPU_max_cube_map_size();
        int reslimit = (U.glreslimit != 0) ?
 -              min_ii(U.glreslimit, size) : size;
 +          min_ii(U.glreslimit, size) : size;
  
        return (w > reslimit || h > reslimit);
  }
@@@ -271,7 -269,8 +271,7 @@@ static struct GPUTextureState 
        int alphablend;
        float anisotropic;
        int gpu_mipmap;
 -      MTexPoly *lasttface;
 -} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL};
 +} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0};
  
  /* Mipmap settings */
  
@@@ -280,13 -279,36 +280,13 @@@ void GPU_set_gpu_mipmapping(int gpu_mip
        int old_value = GTS.gpu_mipmap;
  
        /* only actually enable if it's supported */
 -      GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object;
 +      GTS.gpu_mipmap = gpu_mipmap;
  
        if (old_value != GTS.gpu_mipmap) {
                GPU_free_images();
        }
  }
  
 -static void gpu_generate_mipmap(GLenum target)
 -{
 -      const bool is_ati = GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY);
 -      int target_enabled = 0;
 -
 -      /* work around bug in ATI driver, need to have GL_TEXTURE_2D enabled
 -       * http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation */
 -      if (is_ati) {
 -              target_enabled = glIsEnabled(target);
 -              if (!target_enabled)
 -                      glEnable(target);
 -      }
 -
 -      /* TODO: simplify when we transition to GL >= 3 */
 -      if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object)
 -              glGenerateMipmap(target);
 -      else if (GLEW_EXT_framebuffer_object)
 -              glGenerateMipmapEXT(target);
 -
 -      if (is_ati && !target_enabled)
 -              glDisable(target);
 -}
 -
  void GPU_set_mipmap(bool mipmap)
  {
        if (GTS.domipmap != mipmap) {
@@@ -393,16 -415,43 +393,16 @@@ static unsigned int *gpu_get_image_bind
        return bind;
  }
  
 -void GPU_clear_tpage(bool force)
 -{
 -      if (GTS.lasttface == NULL && !force)
 -              return;
 -      
 -      GTS.lasttface = NULL;
 -      GTS.curtile = 0;
 -      GTS.curima = NULL;
 -      if (GTS.curtilemode != 0) {
 -              glMatrixMode(GL_TEXTURE);
 -              glLoadIdentity();
 -              glMatrixMode(GL_MODELVIEW);
 -      }
 -      GTS.curtilemode = 0;
 -      GTS.curtileXRep = 0;
 -      GTS.curtileYRep = 0;
 -      GTS.alphablend = -1;
 -      
 -      glDisable(GL_BLEND);
 -      glDisable(GL_TEXTURE_2D);
 -      glDisable(GL_TEXTURE_GEN_S);
 -      glDisable(GL_TEXTURE_GEN_T);
 -      glDisable(GL_ALPHA_TEST);
 -}
 -
  static void gpu_set_alpha_blend(GPUBlendMode alphablend)
  {
        if (alphablend == GPU_BLEND_SOLID) {
                glDisable(GL_BLEND);
 -              glDisable(GL_ALPHA_TEST);
                glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
 -              glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +              glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        }
        else if (alphablend == GPU_BLEND_ADD) {
                glEnable(GL_BLEND);
                glBlendFunc(GL_ONE, GL_ONE);
 -              glDisable(GL_ALPHA_TEST);
                glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
        }
        else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) {
  
                /* for OpenGL render we use the alpha channel, this makes alpha blend correct */
                glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 -              
 +
                /* if U.glalphaclip == 1.0, some cards go bonkers...
                 * turn off alpha test in this case */
  
 -              /* added after 2.45 to clip alpha */
 -              if (U.glalphaclip == 1.0f) {
 -                      glDisable(GL_ALPHA_TEST);
 -              }
 -              else {
 -                      glEnable(GL_ALPHA_TEST);
 -                      glAlphaFunc(GL_GREATER, U.glalphaclip);
 -              }
        }
        else if (alphablend == GPU_BLEND_CLIP) {
                glDisable(GL_BLEND);
                glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
 -              glEnable(GL_ALPHA_TEST);
 -              glAlphaFunc(GL_GREATER, 0.5f);
        }
        else if (alphablend == GPU_BLEND_ALPHA_TO_COVERAGE) {
 -              glEnable(GL_ALPHA_TEST);
 -              glAlphaFunc(GL_GREATER, U.glalphaclip);
                glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
        }
  }
  
 -static void gpu_verify_alpha_blend(int alphablend)
 -{
 -      /* verify alpha blending modes */
 -      if (GTS.alphablend == alphablend)
 -              return;
 -
 -      gpu_set_alpha_blend(alphablend);
 -      GTS.alphablend = alphablend;
 -}
 -
 -static void gpu_verify_reflection(Image *ima)
 -{
 -      if (ima && (ima->flag & IMA_REFLECT)) {
 -              /* enable reflection mapping */
 -              glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
 -              glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
 -
 -              glEnable(GL_TEXTURE_GEN_S);
 -              glEnable(GL_TEXTURE_GEN_T);
 -      }
 -      else {
 -              /* disable reflection mapping */
 -              glDisable(GL_TEXTURE_GEN_S);
 -              glDisable(GL_TEXTURE_GEN_T);
 -      }
 -}
 -
  typedef struct VerifyThreadData {
        ImBuf *ibuf;
        float *srgb_frect;
@@@ -446,6 -534,8 +446,6 @@@ static void gpu_verify_high_bit_srgb_bu
                                    ibuf->x, height,
                                    ibuf->x, ibuf->x);
        IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height);
 -      /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */
 -      IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height);
  }
  
  static void verify_thread_do(void *data_v,
@@@ -514,6 -604,19 +514,6 @@@ int GPU_verify_image
                return (ima != NULL);
        }
  
 -      /* if tiling mode or repeat changed, change texture matrix to fit */
 -      if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep ||
 -          GTS.curtileYRep != GTS.tileYRep)
 -      {
 -              glMatrixMode(GL_TEXTURE);
 -              glLoadIdentity();
 -
 -              if (ima && (ima->tpageflag & IMA_TILES))
 -                      glScalef(ima->xrep, ima->yrep, 1.0f);
 -
 -              glMatrixMode(GL_MODELVIEW);
 -      }
 -
        /* check if we have a valid image */
        if (ima == NULL || ima->ok == 0)
                return 0;
                GPU_free_image(ima);
                ima->tpageflag &= ~IMA_TPAGE_REFRESH;
        }
 -      
 +
        if (GTS.tilemode) {
                /* tiled mode */
                if (ima->repbind == NULL) gpu_make_repbind(ima);
                if (GTS.tile >= ima->totbind) GTS.tile = 0;
 -              
 +
                /* this happens when you change repeat buttons */
                if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile];
                else bind = gpu_get_image_bindcode(ima, textarget);
 -              
 +
                if (*bind == 0) {
                        short texwindx = ibuf->x / ima->xrep;
                        short texwindy = ibuf->y / ima->yrep;
 -                      
 +
                        if (GTS.tile >= ima->xrep * ima->yrep)
                                GTS.tile = ima->xrep * ima->yrep - 1;
 -      
 +
                        short texwinsy = GTS.tile / ima->xrep;
                        short texwinsx = GTS.tile - texwinsy * ima->xrep;
 -      
 +
                        texwinsx *= texwindx;
                        texwinsy *= texwindy;
 -      
 +
                        tpx = texwindx;
                        tpy = texwindy;
  
  
                                memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
                        }
 -                      
 +
                        rect = tilerect;
                }
        }
        else
  #endif
                GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
 -      
 +
        /* mark as non-color data texture */
        if (*bind) {
                if (is_data)
 -                      ima->tpageflag |= IMA_GLBIND_IS_DATA;   
 +                      ima->tpageflag |= IMA_GLBIND_IS_DATA;
                else
 -                      ima->tpageflag &= ~IMA_GLBIND_IS_DATA;  
 +                      ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
        }
  
        /* clean up */
@@@ -755,6 -858,30 +755,6 @@@ void GPU_create_gl_tex
        int tpx = rectw;
        int tpy = recth;
  
 -      /* scale if not a power of two. this is not strictly necessary for newer
 -       * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures 
 -       * Then don't bother scaling for hardware that supports NPOT textures! */
 -      if (textarget == GL_TEXTURE_2D &&
 -          ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) ||
 -           is_over_resolution_limit(textarget, rectw, recth)))
 -      {
 -              rectw = smaller_power_of_2_limit(rectw);
 -              recth = smaller_power_of_2_limit(recth);
 -
 -              if (use_high_bit_depth) {
 -                      ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
 -                      IMB_scaleImBuf(ibuf, rectw, recth);
 -
 -                      frect = ibuf->rect_float;
 -              }
 -              else {
 -                      ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
 -                      IMB_scaleImBuf(ibuf, rectw, recth);
 -
 -                      rect = ibuf->rect;
 -              }
 -      }
 -
        /* create image */
        glGenTextures(1, (GLuint *)bind);
        glBindTexture(textarget, *bind);
  
                if (GPU_get_mipmap() && mipmap) {
                        if (GTS.gpu_mipmap) {
 -                              gpu_generate_mipmap(GL_TEXTURE_2D);
 +                              glGenerateMipmap(GL_TEXTURE_2D);
                        }
                        else {
                                int i;
  
                        if (GPU_get_mipmap() && mipmap) {
                                if (GTS.gpu_mipmap) {
 -                                      gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP);
 +                                      glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
                                }
                                else {
                                        if (!ibuf) {
                                                if (mip_cube_map) {
                                                        for (int j = 0; j < 6; j++) {
                                                                glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i,
 -                                                                      informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
 +                                                                  informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
                                                        }
                                                }
                                                gpu_del_cube_map(mip_cube_map);
@@@ -929,7 -1056,7 +929,7 @@@ bool GPU_upload_dxt_texture(ImBuf *ibuf
                size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
  
                glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
 -                      0, size, ibuf->dds_data.data + offset);
 +                  0, size, ibuf->dds_data.data + offset);
  
                offset += size;
                width >>= 1;
@@@ -964,6 -1091,62 +964,6 @@@ void GPU_create_gl_tex_compressed
        }
  #endif
  }
 -static void gpu_verify_repeat(Image *ima)
 -{
 -      /* set either clamp or repeat in X/Y */
 -      if (ima->tpageflag & IMA_CLAMP_U)
 -              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 -      else
 -              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 -
 -      if (ima->tpageflag & IMA_CLAMP_V)
 -              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 -      else
 -              glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 -}
 -
 -int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend)
 -{
 -      /* check if we need to clear the state */
 -      if (mtexpoly == NULL) {
 -              GPU_clear_tpage(false);
 -              return 0;
 -      }
 -
 -      Image *ima = mtexpoly->tpage;
 -      GTS.lasttface = mtexpoly;
 -
 -      gpu_verify_alpha_blend(alphablend);
 -      gpu_verify_reflection(ima);
 -
 -      if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) {
 -              GTS.curtile = GTS.tile;
 -              GTS.curima = GTS.ima;
 -              GTS.curtilemode = GTS.tilemode;
 -              GTS.curtileXRep = GTS.tileXRep;
 -              GTS.curtileYRep = GTS.tileYRep;
 -
 -              glEnable(GL_TEXTURE_2D);
 -      }
 -      else {
 -              glDisable(GL_TEXTURE_2D);
 -              
 -              GTS.curtile = 0;
 -              GTS.curima = NULL;
 -              GTS.curtilemode = 0;
 -              GTS.curtileXRep = 0;
 -              GTS.curtileYRep = 0;
 -
 -              return 0;
 -      }
 -      
 -      gpu_verify_repeat(ima);
 -      
 -      /* Did this get lost in the image recode? */
 -      /* BKE_image_tag_time(ima);*/
 -
 -      return 1;
 -}
  
  /* these two functions are called on entering and exiting texture paint mode,
   * temporary disabling/enabling mipmapping on all images for quick texture
@@@ -1023,7 -1206,9 +1023,7 @@@ void GPU_paint_set_mipmap(bool mipmap
  /* check if image has been downscaled and do scaled partial update */
  static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
  {
 -      if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) ||
 -          is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y))
 -      {
 +      if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) {
                int x_limit = smaller_power_of_2_limit(ibuf->x);
                int y_limit = smaller_power_of_2_limit(ibuf->y);
  
                }
  
                if (GPU_get_mipmap()) {
 -                      gpu_generate_mipmap(GL_TEXTURE_2D);
 +                      glGenerateMipmap(GL_TEXTURE_2D);
                }
                else {
                        ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
@@@ -1111,7 -1296,7 +1111,7 @@@ void GPU_paint_update_image(Image *ima
                        float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf");
                        bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
                        IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
 -                      
 +
                        if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
                                MEM_freeN(buffer);
                                BKE_image_release_ibuf(ima, ibuf, NULL);
                        /* we have already accounted for the case where GTS.gpu_mipmap is false
                         * so we will be using GPU mipmap generation here */
                        if (GPU_get_mipmap()) {
 -                              gpu_generate_mipmap(GL_TEXTURE_2D);
 +                              glGenerateMipmap(GL_TEXTURE_2D);
                        }
                        else {
                                ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
                glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
  
                glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
 -                      GL_UNSIGNED_BYTE, ibuf->rect);
 +                  GL_UNSIGNED_BYTE, ibuf->rect);
  
                glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
                glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
  
                /* see comment above as to why we are using gpu mipmap generation here */
                if (GPU_get_mipmap()) {
 -                      gpu_generate_mipmap(GL_TEXTURE_2D);
 +                      glGenerateMipmap(GL_TEXTURE_2D);
                }
                else {
                        ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
@@@ -1176,9 -1361,9 +1176,9 @@@ void GPU_update_images_framechange(void
                if (ima->tpageflag & IMA_TWINANIM) {
                        if (ima->twend >= ima->xrep * ima->yrep)
                                ima->twend = ima->xrep * ima->yrep - 1;
 -              
 +
                        /* check: is bindcode not in the array? free. (to do) */
 -                      
 +
                        ima->lastframe++;
                        if (ima->lastframe > ima->twend)
                                ima->lastframe = ima->twsta;
@@@ -1201,9 -1386,9 +1201,9 @@@ int GPU_update_image_time(Image *ima, d
  
        if (ima->tpageflag & IMA_TWINANIM) {
                if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
 -              
 +
                /* check: is the bindcode not in the array? Then free. (still to do) */
 -              
 +
                float diff = (float)((float)time - ima->lastupdate);
                inc = (int)(diff * (float)ima->animspeed);
  
@@@ -1252,60 -1437,31 +1252,60 @@@ void GPU_create_smoke(SmokeModifierDat
                        if (smoke_has_colors(sds->fluid)) {
                                float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
                                smoke_get_rgba(sds->fluid, data, 0);
 -                              sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
 +                              sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL);
                                MEM_freeN(data);
                        }
                        /* density only */
                        else {
 -                              sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid));
 +                              sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
 +                                                               GPU_R8, smoke_get_density(sds->fluid), NULL);
 +
 +                              /* Swizzle the RGBA components to read the Red channel so
 +                               * that the shader stay the same for colored and non color
 +                               * density textures. */
 +                              GPU_texture_bind(sds->tex, 0);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
 +                              GPU_texture_unbind(sds->tex);
                        }
 -                      sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL;
 +                      sds->tex_flame = (smoke_has_fuel(sds->fluid)) ?
 +                                        GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
 +                                        GPU_R8, smoke_get_flame(sds->fluid), NULL) :
 +                                        NULL;
                }
                else if (!sds->tex && highres) {
                        /* rgba texture for color + density */
                        if (smoke_turbulence_has_colors(sds->wt)) {
                                float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
                                smoke_turbulence_get_rgba(sds->wt, data, 0);
 -                              sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
 +                              sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL);
                                MEM_freeN(data);
                        }
                        /* density only */
                        else {
 -                              sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt));
 +                              sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
 +                                                                      GPU_R8, smoke_turbulence_get_density(sds->wt), NULL);
 +
 +                              /* Swizzle the RGBA components to read the Red channel so
 +                               * that the shader stay the same for colored and non color
 +                               * density textures. */
 +                              GPU_texture_bind(sds->tex, 0);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
 +                              glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
 +                              GPU_texture_unbind(sds->tex);
                        }
 -                      sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL;
 +                      sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ?
 +                                        GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
 +                                                                     GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL) :
 +                                        NULL;
                }
  
 -              sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow);
 +              sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
 +                                                      GPU_R8, sds->shadow, NULL);
        }
  #else // WITH_SMOKE
        (void)highres;
@@@ -1372,7 -1528,7 +1372,7 @@@ void GPU_free_image(Image *ima
        /* free repeated image binding */
        if (ima->repbind) {
                glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
 -      
 +
                MEM_freeN(ima->repbind);
                ima->repbind = NULL;
        }
@@@ -1445,7 -1601,7 +1445,7 @@@ typedef struct GPUMaterialFixed 
        float spec[3];
        int hard;
        float alpha;
 -} GPUMaterialFixed; 
 +} GPUMaterialFixed;
  
  static struct GPUMaterialState {
        GPUMaterialFixed (*matbuf);
        Material *gmatbuf_fixed[FIXEDMAT];
        Material *gboundmat;
        Object *gob;
 +      eObjectMode gob_object_mode;
        DupliObject *dob;
        Scene *gscene;
        int glay;
 -      bool gscenelock;
        float (*gviewmat)[4];
        float (*gviewinv)[4];
        float (*gviewcamtexcofac);
@@@ -1501,12 -1657,12 +1501,12 @@@ static void gpu_material_to_fixed
                copy_v3_v3(smat->spec, &bmat->specr);
                smat->alpha = 1.0f;
                smat->hard = CLAMPIS(bmat->har, 0, 128);
 -              
 +
                if (dimdown) {
                        mul_v3_fl(smat->diff, 0.8f);
                        mul_v3_fl(smat->spec, 0.5f);
                }
 -              
 +
                if (gamma) {
                        linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
                        linearrgb_to_srgb_v3_v3(smat->spec, smat->spec);
  
                if (bmat->shade_flag & MA_OBCOLOR)
                        mul_v3_v3(smat->diff, ob->col);
 -              
 +
                mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec);
                smat->hard = CLAMPIS(bmat->har, 1, 128);
                smat->alpha = 1.0f;
@@@ -1554,8 -1710,8 +1554,8 @@@ void GPU_end_dupli_object(void
  }
  
  void GPU_begin_object_materials(
 -        View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob,
 -        bool glsl, bool *do_alpha_after)
 +        View3D *v3d, RegionView3D *rv3d, Scene *scene, ViewLayer *view_layer, Object *ob,
 +        bool glsl, const eObjectMode object_mode, bool *do_alpha_after)
  {
        Material *ma;
        GPUMaterial *gpumat;
  
  #ifdef WITH_GAMEENGINE
        if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
 -              ob = BKE_object_lod_matob_get(ob, scene);
 +              ob = BKE_object_lod_matob_get(ob, view_layer, object_mode);
        }
 +#else
 +      UNUSED_VARS(view_layer);
  #endif
  
        /* initialize state */
                GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0;
  
        GMS.gob = ob;
 +      GMS.gob_object_mode = object_mode;
        GMS.gscene = scene;
        GMS.is_opensubdiv = use_opensubdiv;
        GMS.totmat = use_matcap ? 1 : ob->totcol + 1;  /* materials start from 1, default material is 0 */
        GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */
 -      GMS.gscenelock = (v3d->scenelock != 0);
        GMS.gviewmat = rv3d->viewmat;
        GMS.gviewinv = rv3d->viewinv;
        GMS.gviewcamtexcofac = rv3d->viewcamtexcofac;
        GMS.is_alpha_pass = (v3d->transp != false);
        if (GMS.use_alpha_pass)
                *do_alpha_after = false;
 -      
 +
        if (GMS.totmat > FIXEDMAT) {
                GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf");
                GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf");
  
                /* do material 1 too, for displists! */
                memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
 -      
 +
                GMS.alphablend[0] = GPU_BLEND_SOLID;
        }
        else {
 -      
 +
                /* no materials assigned? */
                if (ob->totcol == 0) {
                        gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true);
  
                        GMS.alphablend[0] = GPU_BLEND_SOLID;
                }
 -              
 +
                /* setup materials */
                for (a = 1; a <= ob->totcol; a++) {
                        /* find a suitable material */
@@@ -1730,12 -1884,14 +1730,14 @@@ static int gpu_get_particle_info(GPUPar
                if (ind >= 0) {
                        ParticleData *p = &dob->particle_system->particles[ind];
  
-                       pi->scalprops[0] = BLI_hash_int_01(ind);
+                       pi->scalprops[0] = ind;
                        pi->scalprops[1] = GMS.gscene->r.cfra - p->time;
                        pi->scalprops[2] = p->lifetime;
                        pi->scalprops[3] = p->size;
  
                        copy_v3_v3(pi->location, p->state.co);
+                       pi->location[3] = BLI_hash_int_01(ind);
                        copy_v3_v3(pi->velocity, p->state.vel);
                        copy_v3_v3(pi->angular_velocity, p->state.ave);
                        return 1;
@@@ -1831,13 -1987,13 +1833,13 @@@ int GPU_object_material_bind(int nr, vo
                                gpu_get_particle_info(&partile_info);
                        }
                        
 -                      if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) {
 +                      if ((GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) != 0) {
                                GPU_get_object_info(object_info, mat);
                        }
  
                        GPU_material_bind(
 -                              gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
 -                              GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
 +                              gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob_object_mode & OB_MODE_TEXTURE_PAINT),
 +                              GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac);
  
                        auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
                        GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info);
@@@ -1908,7 -2064,7 +1910,7 @@@ void GPU_set_material_alpha_blend(int a
  {
        if (GMS.lastalphablend == alphablend)
                return;
 -      
 +
        gpu_set_alpha_blend(alphablend);
        GMS.lastalphablend = alphablend;
  }
@@@ -1979,6 -2135,13 +1981,6 @@@ void GPU_end_object_materials(void
        GMS.gmatbuf = NULL;
        GMS.alphablend = NULL;
        GMS.two_sided_lighting = false;
 -
 -      /* resetting the texture matrix after the scaling needed for tiled textures */
 -      if (GTS.tilemode) {
 -              glMatrixMode(GL_TEXTURE);
 -              glLoadIdentity();
 -              glMatrixMode(GL_MODELVIEW);
 -      }
  }
  
  /* Lights */
@@@ -1992,13 -2155,13 +1994,13 @@@ int GPU_default_lights(void
                U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8;
                U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5;
                U.light[0].spec[3] = 1.0;
 -              
 +
                U.light[1].flag = 0;
                U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1;
                U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8;
                U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5;
                U.light[1].spec[3] = 1.0;
 -      
 +
                U.light[2].flag = 0;
                U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2;
                U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4;
        return count;
  }
  
 -int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho)
 +int GPU_scene_object_lights(ViewLayer *view_layer, float viewmat[4][4], int ortho)
  {
        /* disable all lights */
        for (int count = 0; count < 8; count++)
                GPU_basic_shader_light_set(count, NULL);
 -      
 +
        /* view direction for specular is not computed correct by default in
         * opengl, so we set the settings ourselves */
        GPU_basic_shader_light_set_viewer(!ortho);
  
        int count = 0;
  
 -      for (Base *base = scene->base.first; base; base = base->next) {
 +      for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
                if (base->object->type != OB_LAMP)
                        continue;
  
 -              if (!(base->lay & lay) || !(base->lay & ob->lay))
 -                      continue;
 -
                Lamp *la = base->object->data;
 -              
 +
                /* setup lamp transform */
 -              glPushMatrix();
 -              glLoadMatrixf((float *)viewmat);
 -              
 +              gpuPushMatrix();
 +              gpuLoadMatrix(viewmat);
 +
                /* setup light */
                GPULightData light = {0};
  
                        light.constant_attenuation = 1.0f;
                        light.linear_attenuation = la->att1 / la->dist;
                        light.quadratic_attenuation = la->att2 / (la->dist * la->dist);
 -                      
 +
                        if (la->type == LA_SPOT) {
                                light.type = GPU_LIGHT_SPOT;
                                negate_v3_v3(light.direction, base->object->obmat[2]);
                        else
                                light.type = GPU_LIGHT_POINT;
                }
 -              
 +
                GPU_basic_shader_light_set(count, &light);
 -              
 -              glPopMatrix();
 -              
 +
 +              gpuPopMatrix();
 +
                count++;
                if (count == 8)
                        break;
        return count;
  }
  
 -static void gpu_multisample(bool enable)
 +static void gpu_disable_multisample()
  {
  #ifdef __linux__
        /* changing multisample from the default (enabled) causes problems on some
        }
  
        if (toggle_ok) {
 -              if (enable)
 -                      glEnable(GL_MULTISAMPLE);
 -              else
 -                      glDisable(GL_MULTISAMPLE);
 +              glDisable(GL_MULTISAMPLE);
        }
  #else
 -      if (enable)
 -              glEnable(GL_MULTISAMPLE);
 -      else
 -              glDisable(GL_MULTISAMPLE);
 +      glDisable(GL_MULTISAMPLE);
  #endif
  }
  
  
  void GPU_state_init(void)
  {
 -      float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
 -      float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
 -      
 -      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
 -      glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
 -      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
 -      glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35);
 -      glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
 -
        GPU_default_lights();
 -      
 +
 +      GPU_disable_program_point_size();
 +
 +      glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
 +
        glDepthFunc(GL_LEQUAL);
 -      /* scaling matrices */
 -      glEnable(GL_NORMALIZE);
  
 -      glDisable(GL_ALPHA_TEST);
        glDisable(GL_BLEND);
        glDisable(GL_DEPTH_TEST);
 -      glDisable(GL_FOG);
 -      glDisable(GL_LIGHTING);
 -      glDisable(GL_COLOR_MATERIAL);
 -      glDisable(GL_LOGIC_OP);
 +      glDisable(GL_COLOR_LOGIC_OP);
        glDisable(GL_STENCIL_TEST);
 -      glDisable(GL_TEXTURE_1D);
 -      glDisable(GL_TEXTURE_2D);
 -      glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 -
 -      /* default disabled, enable should be local per function */
 -      glDisableClientState(GL_VERTEX_ARRAY);
 -      glDisableClientState(GL_NORMAL_ARRAY);
 -      glDisableClientState(GL_COLOR_ARRAY);
 -      glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 -      
 -      glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
 -      glPixelTransferi(GL_RED_SCALE, 1);
 -      glPixelTransferi(GL_RED_BIAS, 0);
 -      glPixelTransferi(GL_GREEN_SCALE, 1);
 -      glPixelTransferi(GL_GREEN_BIAS, 0);
 -      glPixelTransferi(GL_BLUE_SCALE, 1);
 -      glPixelTransferi(GL_BLUE_BIAS, 0);
 -      glPixelTransferi(GL_ALPHA_SCALE, 1);
 -      glPixelTransferi(GL_ALPHA_BIAS, 0);
 -      
 -      glPixelTransferi(GL_DEPTH_BIAS, 0);
 -      glPixelTransferi(GL_DEPTH_SCALE, 1);
 -      glDepthRange(0.0, 1.0);
  
 -      glMatrixMode(GL_TEXTURE);
 -      glLoadIdentity();
 -      glMatrixMode(GL_MODELVIEW);
 +      glDepthRange(0.0, 1.0);
  
        glFrontFace(GL_CCW);
        glCullFace(GL_BACK);
        glDisable(GL_CULL_FACE);
  
 -      gpu_multisample(false);
 +      gpu_disable_multisample();
 +}
  
 -      GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
 +void GPU_enable_program_point_size(void)
 +{
 +      glEnable(GL_PROGRAM_POINT_SIZE);
 +}
 +
 +void GPU_disable_program_point_size(void)
 +{
 +      glDisable(GL_PROGRAM_POINT_SIZE);
  }
  
  #ifdef WITH_OPENSUBDIV
@@@ -2302,10 -2502,10 +2304,10 @@@ void GPU_select_to_index_array(unsigne
  {
  #define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
        for (i = size; i--; col++) { \
 -              if ((c = *col)) { \
 -                      *col = INDEX_FROM_BUF_BITS(c); \
 -              } \
 -      } ((void)0)
 +          if ((c = *col)) { \
 +              *col = INDEX_FROM_BUF_BITS(c); \
 +        } \
 +    } ((void)0)
  
        if (size > 0) {
                unsigned int i, c;
  #undef INDEX_BUF_ARRAY
  }
  
 +#define STATE_STACK_DEPTH 16
 +
 +typedef struct {
 +      eGPUAttribMask mask;
 +
 +      /* GL_ENABLE_BIT */
 +      unsigned int is_blend : 1;
 +      unsigned int is_cull_face : 1;
 +      unsigned int is_depth_test : 1;
 +      unsigned int is_dither : 1;
 +      unsigned int is_lighting : 1;
 +      unsigned int is_line_smooth : 1;
 +      unsigned int is_color_logic_op : 1;
 +      unsigned int is_multisample : 1;
 +      unsigned int is_polygon_offset_line : 1;
 +      unsigned int is_polygon_offset_fill : 1;
 +      unsigned int is_polygon_smooth : 1;
 +      unsigned int is_sample_alpha_to_coverage : 1;
 +      unsigned int is_scissor_test : 1;
 +      unsigned int is_stencil_test : 1;
 +
 +      bool is_clip_plane[6];
 +
 +      /* GL_DEPTH_BUFFER_BIT */
 +      /* unsigned int is_depth_test : 1; */
 +      int depth_func;
 +      double depth_clear_value;
 +      bool depth_write_mask;
 +
 +      /* GL_SCISSOR_BIT */
 +      int scissor_box[4];
 +      /* unsigned int is_scissor_test : 1; */
 +
 +      /* GL_VIEWPORT_BIT */
 +      int viewport[4];
 +      double near_far[2];
 +}  GPUAttribValues;
 +
 +typedef struct {
 +      GPUAttribValues attrib_stack[STATE_STACK_DEPTH];
 +      unsigned int top;
 +} GPUAttribStack;
 +
 +static GPUAttribStack state = {
 +      .top = 0
 +};
 +
 +#define AttribStack state
 +#define Gwn_VertAttr state.attrib_stack[state.top]
 +
 +/**
 + * Replacement for glPush/PopAttributes
 + *
 + * We don't need to cover all the options of legacy OpenGL
 + * but simply the ones used by Blender.
 + */
 +void gpuPushAttrib(eGPUAttribMask mask)
 +{
 +      Gwn_VertAttr.mask = mask;
 +
 +      if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
 +              Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
 +              glGetIntegerv(GL_DEPTH_FUNC, &Gwn_VertAttr.depth_func);
 +              glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Gwn_VertAttr.depth_clear_value);
 +              glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Gwn_VertAttr.depth_write_mask);
 +      }
 +
 +      if ((mask & GPU_ENABLE_BIT) != 0) {
 +              Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND);
 +
 +              for (int i = 0; i < 6; i++) {
 +                      Gwn_VertAttr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
 +              }
 +
 +              Gwn_VertAttr.is_cull_face = glIsEnabled(GL_CULL_FACE);
 +              Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
 +              Gwn_VertAttr.is_dither = glIsEnabled(GL_DITHER);
 +              Gwn_VertAttr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
 +              Gwn_VertAttr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
 +              Gwn_VertAttr.is_multisample = glIsEnabled(GL_MULTISAMPLE);
 +              Gwn_VertAttr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
 +              Gwn_VertAttr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
 +              Gwn_VertAttr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
 +              Gwn_VertAttr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
 +              Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
 +              Gwn_VertAttr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
 +      }
 +
 +      if ((mask & GPU_SCISSOR_BIT) != 0) {
 +              Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
 +              glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Gwn_VertAttr.scissor_box);
 +      }
 +
 +      if ((mask & GPU_VIEWPORT_BIT) != 0) {
 +              glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Gwn_VertAttr.near_far);
 +              glGetIntegerv(GL_VIEWPORT, (GLint *)&Gwn_VertAttr.viewport);
 +      }
 +
 +      if ((mask & GPU_BLEND_BIT) != 0) {
 +              Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND);
 +      }
 +
 +      BLI_assert(AttribStack.top < STATE_STACK_DEPTH);
 +      AttribStack.top++;
 +}
 +
 +static void restore_mask(GLenum cap, const bool value)
 +{
 +      if (value) {
 +              glEnable(cap);
 +      }
 +      else {
 +              glDisable(cap);
 +      }
 +}
 +
 +void gpuPopAttrib(void)
 +{
 +      BLI_assert(AttribStack.top > 0);
 +      AttribStack.top--;
 +
 +      GLint mask = Gwn_VertAttr.mask;
 +
 +      if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
 +              restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test);
 +              glDepthFunc(Gwn_VertAttr.depth_func);
 +              glClearDepth(Gwn_VertAttr.depth_clear_value);
 +              glDepthMask(Gwn_VertAttr.depth_write_mask);
 +      }
 +
 +      if ((mask & GPU_ENABLE_BIT) != 0) {
 +              restore_mask(GL_BLEND, Gwn_VertAttr.is_blend);
 +
 +              for (int i = 0; i < 6; i++) {
 +                      restore_mask(GL_CLIP_PLANE0 + i, Gwn_VertAttr.is_clip_plane[i]);
 +              }
 +
 +              restore_mask(GL_CULL_FACE, Gwn_VertAttr.is_cull_face);
 +              restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test);
 +              restore_mask(GL_DITHER, Gwn_VertAttr.is_dither);
 +              restore_mask(GL_LINE_SMOOTH, Gwn_VertAttr.is_line_smooth);
 +              restore_mask(GL_COLOR_LOGIC_OP, Gwn_VertAttr.is_color_logic_op);
 +              restore_mask(GL_MULTISAMPLE, Gwn_VertAttr.is_multisample);
 +              restore_mask(GL_POLYGON_OFFSET_LINE, Gwn_VertAttr.is_polygon_offset_line);
 +              restore_mask(GL_POLYGON_OFFSET_FILL, Gwn_VertAttr.is_polygon_offset_fill);
 +              restore_mask(GL_POLYGON_SMOOTH, Gwn_VertAttr.is_polygon_smooth);
 +              restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Gwn_VertAttr.is_sample_alpha_to_coverage);
 +              restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test);
 +              restore_mask(GL_STENCIL_TEST, Gwn_VertAttr.is_stencil_test);
 +      }
 +
 +      if ((mask & GPU_VIEWPORT_BIT) != 0) {
 +              glViewport(Gwn_VertAttr.viewport[0], Gwn_VertAttr.viewport[1], Gwn_VertAttr.viewport[2], Gwn_VertAttr.viewport[3]);
 +              glDepthRange(Gwn_VertAttr.near_far[0], Gwn_VertAttr.near_far[1]);
 +      }
 +
 +      if ((mask & GPU_SCISSOR_BIT) != 0) {
 +              restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test);
 +              glScissor(Gwn_VertAttr.scissor_box[0], Gwn_VertAttr.scissor_box[1], Gwn_VertAttr.scissor_box[2], Gwn_VertAttr.scissor_box[3]);
 +      }
 +
 +      if ((mask & GPU_BLEND_BIT) != 0) {
 +              restore_mask(GL_BLEND, Gwn_VertAttr.is_blend);
 +      }
 +}
 +
 +#undef Gwn_VertAttr
 +#undef AttribStack
 +
  /** \} */
index 4efb8ca07b20d4d5c59f9a645c3c73ff23a2925b,edb6c9a29f9c5a0cddc2e4aee8f0cc4f5fb698ea..2d7b941503094d2ca4caa8a33d22329da16458a9
  #include "BLI_math.h"
  #include "BLI_blenlib.h"
  #include "BLI_utildefines.h"
 +#include "BLI_rand.h"
  
  #include "BKE_anim.h"
  #include "BKE_colorband.h"
  #include "BKE_colortools.h"
  #include "BKE_global.h"
  #include "BKE_image.h"
 +#include "BKE_layer.h"
  #include "BKE_main.h"
  #include "BKE_node.h"
  #include "BKE_scene.h"
  
  #include "GPU_extensions.h"
  #include "GPU_framebuffer.h"
 +#include "GPU_lamp.h"
  #include "GPU_material.h"
  #include "GPU_shader.h"
  #include "GPU_texture.h"
 +#include "GPU_uniformbuffer.h"
  
  #include "gpu_codegen.h"
 +#include "gpu_lamp_private.h"
  
  #ifdef WITH_OPENSUBDIV
  #  include "BKE_DerivedMesh.h"
@@@ -97,15 -92,12 +97,15 @@@ static struct GPUWorld 
  } GPUWorld;
  
  struct GPUMaterial {
 -      Scene *scene;
 +      Scene *scene; /* DEPRECATED was only usefull for lamps */
        Material *ma;
  
        /* material for mesh surface, worlds or something else.
         * some code generation is done differently depending on the use case */
 -      int type;
 +      int type; /* DEPRECATED */
 +
 +      const void *engine_type;   /* attached engine type */
 +      int options;    /* to identify shader variations (shadow, probe, world background...) */
        
        /* for creating the material */
        ListBase nodes;
        bool bound;
  
        bool is_opensubdiv;
 -};
 -
 -struct GPULamp {
 -      Scene *scene;
 -      Object *ob;
 -      Object *par;
 -      Lamp *la;
 -
 -      int type, mode, lay, hide;
 -
 -      float dynenergy, dyncol[3];
 -      float energy, col[3];
 -
 -      float co[3], vec[3];
 -      float dynco[3], dynvec[3];
 -      float obmat[4][4];
 -      float imat[4][4];
 -      float dynimat[4][4];
 -
 -      float spotsi, spotbl, k;
 -      float spotvec[2];
 -      float dyndist, dynatt1, dynatt2;
 -      float dist, att1, att2;
 -      float coeff_const, coeff_lin, coeff_quad;
 -      float shadow_color[3];
 -
 -      float bias, d, clipend;
 -      int size;
 -
 -      int falloff_type;
 -      struct CurveMapping *curfalloff;
  
 -      float winmat[4][4];
 -      float viewmat[4][4];
 -      float persmat[4][4];
 -      float dynpersmat[4][4];
 -
 -      GPUFrameBuffer *fb;
 -      GPUFrameBuffer *blurfb;
 -      GPUTexture *tex;
 -      GPUTexture *depthtex;
 -      GPUTexture *blurtex;
 +      /* XXX: Should be in Material. But it depends on the output node
 +       * used and since the output selection is difference for GPUMaterial...
 +       */
 +      int domain;
 +
 +      GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
 +      GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
 +      GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
 +      float *sss_radii; /* UBO containing SSS profile. */
 +      int sss_samples;
 +      short int *sss_falloff;
 +      float *sss_sharpness;
 +      bool sss_dirty;
 +};
  
 -      ListBase materials;
 +enum {
 +      GPU_DOMAIN_SURFACE    = (1 << 0),
 +      GPU_DOMAIN_VOLUME     = (1 << 1),
 +      GPU_DOMAIN_SSS        = (1 << 2)
  };
  
  /* Forward declaration so shade_light_textures() can use this, while still keeping the code somewhat organized */
@@@ -273,18 -289,21 +273,18 @@@ void GPU_material_free(ListBase *gpumat
                if (material->pass)
                        GPU_pass_free(material->pass);
  
 -              for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) {
 -                      GPULamp *lamp = nlink->data;
 +              if (material->ubo != NULL) {
 +                      GPU_uniformbuffer_free(material->ubo);
 +              }
  
 -                      if (material->ma) {
 -                              Material *ma = material->ma;
 -                              
 -                              LinkData *next = NULL;
 -                              for (LinkData *mlink = lamp->materials.first; mlink; mlink = next) {
 -                                      next = mlink->next;
 -                                      if (mlink->data == ma)
 -                                              BLI_freelinkN(&lamp->materials, mlink);
 -                              }
 -                      }
 +              if (material->sss_tex_profile != NULL) {
 +                      GPU_texture_free(material->sss_tex_profile);
                }
 -              
 +
 +              if (material->sss_profile != NULL) {
 +                      GPU_uniformbuffer_free(material->sss_profile);
 +              }
 +
                BLI_freelistN(&material->lamps);
  
                MEM_freeN(material);
        BLI_freelistN(gpumaterial);
  }
  
 -bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma)
 -{
 -      if (lamp->hide)
 -              return false;
 -      else if (srl && srl->light_override)
 -              return BKE_group_object_exists(srl->light_override, lamp->ob);
 -      else if (ma && ma->group)
 -              return BKE_group_object_exists(ma->group, lamp->ob);
 -      else
 -              return true;
 -}
 -
  void GPU_material_bind(
          GPUMaterial *material, int oblay, int viewlay, double time, int mipmap,
 -        float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock)
 +        float viewmat[4][4], float viewinv[4][4], float camerafactors[4])
  {
        if (material->pass) {
                GPUShader *shader = GPU_pass_shader(material->pass);
 -              SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL;
 -
 -              if (srl)
 -                      viewlay &= srl->lay;
  
                /* handle layer lamps */
                if (material->type == GPU_MATERIAL_TYPE_MESH) {
                                GPULamp *lamp = nlink->data;
                                
                                if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) &&
 -                                  GPU_lamp_visible(lamp, srl, material->ma))
 +                                  GPU_lamp_visible(lamp, material->ma))
                                {
                                        lamp->dynenergy = lamp->energy;
                                        copy_v3_v3(lamp->dyncol, lamp->col);
@@@ -417,7 -452,7 +417,7 @@@ void GPU_material_bind_uniforms
                        GPU_shader_uniform_vector(shader, material->partscalarpropsloc, 4, 1, pi->scalprops);
                }
                if (material->builtins & GPU_PARTICLE_LOCATION) {
-                       GPU_shader_uniform_vector(shader, material->partcoloc, 3, 1, pi->location);
+                       GPU_shader_uniform_vector(shader, material->partcoloc, 4, 1, pi->location);
                }
                if (material->builtins & GPU_PARTICLE_VELOCITY) {
                        GPU_shader_uniform_vector(shader, material->partvel, 3, 1, pi->velocity);
@@@ -455,350 -490,6 +455,350 @@@ GPUMatType GPU_Material_get_type(GPUMat
        return material->type;
  }
  
 +GPUPass *GPU_material_get_pass(GPUMaterial *material)
 +{
 +      return material->pass;
 +}
 +
 +GPUUniformBuffer *GPU_material_get_uniform_buffer(GPUMaterial *material)
 +{
 +      return material->ubo;
 +}
 +
 +/**
 + * Create dynamic UBO from parameters
 + * \param ListBase of BLI_genericNodeN(GPUInput)
 + */
 +void GPU_material_create_uniform_buffer(GPUMaterial *material, ListBase *inputs)
 +{
 +      material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL);
 +}
 +
 +void GPU_material_uniform_buffer_tag_dirty(ListBase *gpumaterials)
 +{
 +      for (LinkData *link = gpumaterials->first; link; link = link->next) {
 +              GPUMaterial *material = link->data;
 +              if (material->ubo != NULL) {
 +                      GPU_uniformbuffer_tag_dirty(material->ubo);
 +              }
 +              if (material->sss_profile != NULL) {
 +                      material->sss_dirty = true;
 +              }
 +      }
 +}
 +
 +/* Eevee Subsurface scattering. */
 +/* Based on Separable SSS. by Jorge Jimenez and Diego Gutierrez */
 +
 +#define SSS_SAMPLES 65
 +#define SSS_EXPONENT 2.0f /* Importance sampling exponent */
 +
 +typedef struct GPUSssKernelData {
 +      float kernel[SSS_SAMPLES][4];
 +      float param[3], max_radius;
 +      int samples;
 +} GPUSssKernelData;
 +
 +static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent)
 +{
 +      float step = 2.0f / (float)(count - 1);
 +      for (int i = 0; i < count; i++) {
 +              float o = ((float)i) * step - 1.0f;
 +              float sign = (o < 0.0f) ? -1.0f : 1.0f;
 +              float ofs = sign * fabsf(powf(o, exponent));
 +              kd->kernel[i][3] = ofs;
 +      }
 +}
 +
 +#define GAUSS_TRUNCATE 12.46f
 +static float gaussian_profile(float r, float radius)
 +{
 +      const float v = radius * radius * (0.25f * 0.25f);
 +      const float Rm = sqrtf(v * GAUSS_TRUNCATE);
 +
 +      if (r >= Rm) {
 +              return 0.0f;
 +      }
 +      return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v);
 +}
 +
 +#define BURLEY_TRUNCATE     16.0f
 +#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
 +static float burley_profile(float r, float d)
 +{
 +      float exp_r_3_d = expf(-r / (3.0f * d));
 +      float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
 +      return (exp_r_d + exp_r_3_d) / (4.0f * d);
 +}
 +
 +static float cubic_profile(float r, float radius, float sharpness)
 +{
 +      float Rm = radius * (1.0f + sharpness);
 +
 +      if (r >= Rm) {
 +              return 0.0f;
 +      }
 +      /* custom variation with extra sharpness, to match the previous code */
 +      const float y = 1.0f / (1.0f + sharpness);
 +      float Rmy, ry, ryinv;
 +
 +      Rmy = powf(Rm, y);
 +      ry = powf(r, y);
 +      ryinv = (r > 0.0f) ? powf(r, y - 1.0f) : 0.0f;
 +
 +      const float Rmy5 = (Rmy * Rmy) * (Rmy * Rmy) * Rmy;
 +      const float f = Rmy - ry;
 +      const float num = f * (f * f) * (y * ryinv);
 +
 +      return (10.0f * num) / (Rmy5 * M_PI);
 +}
 +
 +static float eval_profile(float r, short falloff_type, float sharpness, float param)
 +{
 +      r = fabsf(r);
 +
 +      if (falloff_type == SHD_SUBSURFACE_BURLEY ||
 +          falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
 +      {
 +              return burley_profile(r, param) / BURLEY_TRUNCATE_CDF;
 +      }
 +      else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
 +              return cubic_profile(r, param, sharpness);
 +      }
 +      else {
 +              return gaussian_profile(r, param);
 +      }
 +}
 +
 +/* Resolution for each sample of the precomputed kernel profile */
 +#define INTEGRAL_RESOLUTION 32
 +static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param)
 +{
 +      const float range = x1 - x0;
 +      const float step = range / INTEGRAL_RESOLUTION;
 +      float integral = 0.0f;
 +
 +      for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
 +              float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
 +              float y = eval_profile(x, falloff_type, sharpness, param);
 +              integral += y * step;
 +      }
 +
 +      return integral;
 +}
 +#undef INTEGRAL_RESOLUTION
 +
 +static void compute_sss_kernel(
 +        GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness)
 +{
 +      float rad[3];
 +      /* Minimum radius */
 +      rad[0] = MAX2(radii[0], 1e-15f);
 +      rad[1] = MAX2(radii[1], 1e-15f);
 +      rad[2] = MAX2(radii[2], 1e-15f);
 +
 +      /* Christensen-Burley fitting */
 +      float l[3], d[3];
 +
 +      if (falloff_type == SHD_SUBSURFACE_BURLEY ||
 +          falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
 +      {
 +              mul_v3_v3fl(l, rad, 0.25f * M_1_PI);
 +              const float A = 1.0f;
 +              const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
 +              /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */
 +              mul_v3_v3fl(d, l, 0.6f / s);
 +              mul_v3_v3fl(rad, d, BURLEY_TRUNCATE);
 +              kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
 +
 +              copy_v3_v3(kd->param, d);
 +      }
 +      else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
 +              copy_v3_v3(kd->param, rad);
 +              mul_v3_fl(rad, 1.0f + sharpness);
 +              kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
 +      }
 +      else {
 +              kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
 +
 +              copy_v3_v3(kd->param, rad);
 +      }
 +
 +      /* Compute samples locations on the 1d kernel [-1..1] */
 +      sss_calculate_offsets(kd, sample_ct, SSS_EXPONENT);
 +
 +      /* Weights sum for normalization */
 +      float sum[3] = {0.0f, 0.0f, 0.0f};
 +
 +      /* Compute integral of each sample footprint */
 +      for (int i = 0; i < sample_ct; i++) {
 +              float x0, x1;
 +
 +              if (i == 0) {
 +                      x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f;
 +              }
 +              else {
 +                      x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f;
 +              }
 +
 +              if (i == sample_ct - 1) {
 +                      x1 = kd->kernel[sample_ct - 1][3] + fabsf(kd->kernel[sample_ct - 2][3] - kd->kernel[sample_ct - 1][3]) / 2.0f;
 +              }
 +              else {
 +                      x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f;
 +              }
 +
 +              x0 *= kd->max_radius;
 +              x1 *= kd->max_radius;
 +
 +              kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]);
 +              kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]);
 +              kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]);
 +
 +              sum[0] += kd->kernel[i][0];
 +              sum[1] += kd->kernel[i][1];
 +              sum[2] += kd->kernel[i][2];
 +      }
 +
 +      for (int i = 0; i < 3; ++i) {
 +              if (sum[i] > 0.0f) {
 +                      /* Normalize */
 +                      for (int j = 0; j < sample_ct; j++) {
 +                              kd->kernel[j][i] /= sum[i];
 +                      }
 +              }
 +              else {
 +                      /* Avoid 0 kernel sum. */
 +                      kd->kernel[sample_ct / 2][i] = 1.0f;
 +              }
 +      }
 +
 +      /* Put center sample at the start of the array (to sample first) */
 +      float tmpv[4];
 +      copy_v4_v4(tmpv, kd->kernel[sample_ct / 2]);
 +      for (int i = sample_ct / 2; i > 0; i--) {
 +              copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]);
 +      }
 +      copy_v4_v4(kd->kernel[0], tmpv);
 +
 +      kd->samples = sample_ct;
 +}
 +
 +#define INTEGRAL_RESOLUTION 512
 +static void compute_sss_translucence_kernel(
 +        const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output)
 +{
 +      float (*texels)[4];
 +      texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel");
 +      *output = (float *)texels;
 +
 +      /* Last texel should be black, hence the - 1. */
 +      for (int i = 0; i < resolution - 1; ++i) {
 +              /* Distance from surface. */
 +              float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
 +
 +              /* For each distance d we compute the radiance incomming from an hypothetic parallel plane. */
 +              /* Compute radius of the footprint on the hypothetic plane */
 +              float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d);
 +              float r_step = r_fp / INTEGRAL_RESOLUTION;
 +              float area_accum = 0.0f;
 +              for (float r = 0.0f; r < r_fp; r += r_step) {
 +                      /* Compute distance to the "shading" point through the medium. */
 +                      /* r_step * 0.5f to put sample between the area borders */
 +                      float dist = hypotf(r + r_step * 0.5f, d);
 +
 +                      float profile[3];
 +                      profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]);
 +                      profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]);
 +                      profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]);
 +
 +                      /* Since the profile and configuration are radially symetrical we
 +                       * can just evaluate it once and weight it accordingly */
 +                      float r_next = r + r_step;
 +                      float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r);
 +
 +                      mul_v3_fl(profile, disk_area);
 +                      add_v3_v3(texels[i], profile);
 +                      area_accum += disk_area;
 +              }
 +              /* Normalize over the disk. */
 +              mul_v3_fl(texels[i], 1.0f / (area_accum));
 +      }
 +
 +      /* Normalize */
 +      for (int j = resolution - 2; j > 0; j--) {
 +              texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f;
 +              texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f;
 +              texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f;
 +      }
 +
 +      /* First texel should be white */
 +      texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f;
 +      texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f;
 +      texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f;
 +
 +      /* dim the last few texels for smoother transition */
 +      mul_v3_fl(texels[resolution - 2], 0.25f);
 +      mul_v3_fl(texels[resolution - 3], 0.5f);
 +      mul_v3_fl(texels[resolution - 4], 0.75f);
 +}
 +#undef INTEGRAL_RESOLUTION
 +
 +void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short *falloff_type, float *sharpness)
 +{
 +      material->sss_radii = radii;
 +      material->sss_falloff = falloff_type;
 +      material->sss_sharpness = sharpness;
 +      material->sss_dirty = true;
 +
 +      /* Update / Create UBO */
 +      if (material->sss_profile == NULL) {
 +              material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
 +      }
 +}
 +
 +struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct, GPUTexture **tex_profile)
 +{
 +      if (material->sss_radii == NULL)
 +              return NULL;
 +
 +      if (material->sss_dirty || (material->sss_samples != sample_ct)) {
 +              GPUSssKernelData kd;
 +
 +              float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f;
 +
 +              /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
 +              sharpness *= 0.5f;
 +
 +              compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness);
 +
 +              /* Update / Create UBO */
 +              GPU_uniformbuffer_update(material->sss_profile, &kd);
 +
 +              /* Update / Create Tex */
 +              float *translucence_profile;
 +              compute_sss_translucence_kernel(&kd, 64, *material->sss_falloff, sharpness, &translucence_profile);
 +
 +              if (material->sss_tex_profile != NULL) {
 +                      GPU_texture_free(material->sss_tex_profile);
 +              }
 +
 +              material->sss_tex_profile = GPU_texture_create_1D_custom(64, 4, GPU_RGBA16F, translucence_profile, NULL);
 +
 +              MEM_freeN(translucence_profile);
 +
 +              material->sss_samples = sample_ct;
 +              material->sss_dirty = false;
 +      }
 +
 +      if (tex_profile != NULL) {
 +              *tex_profile = material->sss_tex_profile;
 +      }
 +      return material->sss_profile;
 +}
 +
 +#undef SSS_EXPONENT
 +#undef SSS_SAMPLES
  
  void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs)
  {
@@@ -849,16 -540,6 +849,16 @@@ bool GPU_material_use_world_space_shadi
        return BKE_scene_use_world_space_shading(mat->scene);
  }
  
 +bool GPU_material_use_domain_surface(GPUMaterial *mat)
 +{
 +      return (mat->domain & GPU_DOMAIN_SURFACE);
 +}
 +
 +bool GPU_material_use_domain_volume(GPUMaterial *mat)
 +{
 +      return (mat->domain & GPU_DOMAIN_VOLUME);
 +}
 +
  static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
  {
        GPUNodeLink *visifac;
@@@ -1270,12 -951,14 +1270,12 @@@ static void shade_one_light(GPUShadeInp
                                }
                                
                                add_user_list(&mat->lamps, lamp);
 -                              add_user_list(&lamp->materials, shi->gpumat->ma);
                                return;
                        }
                }
        }
        else if ((mat->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && (lamp->mode & LA_ONLYSHADOW)) {
                add_user_list(&mat->lamps, lamp);
 -              add_user_list(&lamp->materials, shi->gpumat->ma);
                return;
        }
        else
        }
  
        add_user_list(&mat->lamps, lamp);
 -      add_user_list(&lamp->materials, shi->gpumat->ma);
  }
  
  static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
@@@ -2466,73 -2150,6 +2466,73 @@@ GPUMaterial *GPU_material_world(struct 
        return mat;
  }
  
 +GPUMaterial *GPU_material_from_nodetree_find(
 +        ListBase *gpumaterials, const void *engine_type, int options)
 +{
 +      for (LinkData *link = gpumaterials->first; link; link = link->next) {
 +              GPUMaterial *current_material = (GPUMaterial *)link->data;
 +              if (current_material->engine_type == engine_type &&
 +                  current_material->options == options)
 +              {
 +                      return current_material;
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +/**
 + * TODO: This is supposed to replace GPU_material_from_blender/_world in the future
 + *
 + * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials,
 + * This is enforced since constructing other arguments to this function may be expensive
 + * so only do this when they are needed.
 + */
 +GPUMaterial *GPU_material_from_nodetree(
 +        Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options,
 +        const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines)
 +{
 +      GPUMaterial *mat;
 +      GPUNodeLink *outlink;
 +      LinkData *link;
 +      bool has_volume_output, has_surface_output;
 +
 +      /* Caller must re-use materials. */
 +      BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
 +
 +      /* allocate material */
 +      mat = GPU_material_construct_begin(NULL); /* TODO remove GPU_material_construct_begin */
 +      mat->scene = scene;
 +      mat->engine_type = engine_type;
 +      mat->options = options;
 +
 +      ntreeGPUMaterialNodes(ntree, mat, NODE_NEW_SHADING | NODE_NEWER_SHADING);
 +      ntreeGPUMaterialDomain(ntree, &has_surface_output, &has_volume_output);
 +
 +      if (has_surface_output) {
 +              mat->domain |= GPU_DOMAIN_SURFACE;
 +      }
 +      if (has_volume_output) {
 +              mat->domain |= GPU_DOMAIN_VOLUME;
 +      }
 +
 +      /* Let Draw manager finish the construction. */
 +      if (mat->outlink) {
 +              outlink = mat->outlink;
 +              mat->pass = GPU_generate_pass_new(
 +                      mat, &mat->nodes, outlink, &mat->attribs, vert_code, geom_code, frag_lib, defines);
 +      }
 +
 +      /* note that even if building the shader fails in some way, we still keep
 +       * it to avoid trying to compile again and again, and simple do not use
 +       * the actual shader on drawing */
 +
 +      link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
 +      link->data = mat;
 +      BLI_addtail(gpumaterials, link);
 +
 +      return mat;
 +}
  
  GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv)
  {
@@@ -2620,6 -2237,386 +2620,6 @@@ void GPU_materials_free(void
  
  /* Lamps and shadow buffers */
  
 -static void gpu_lamp_calc_winmat(GPULamp *lamp)
 -{
 -      float temp, angle, pixsize, wsize;
 -
 -      if (lamp->type == LA_SUN) {
 -              wsize = lamp->la->shadow_frustum_size;
 -              orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
 -      }
 -      else if (lamp->type == LA_SPOT) {
 -              angle = saacos(lamp->spotsi);
 -              temp = 0.5f * lamp->size * cosf(angle) / sinf(angle);
 -              pixsize = lamp->d / temp;
 -              wsize = pixsize * 0.5f * lamp->size;
 -              /* compute shadows according to X and Y scaling factors */
 -              perspective_m4(
 -                      lamp->winmat,
 -                      -wsize * lamp->spotvec[0], wsize * lamp->spotvec[0],
 -                      -wsize * lamp->spotvec[1], wsize * lamp->spotvec[1],
 -                      lamp->d, lamp->clipend);
 -      }
 -}
 -
 -void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4])
 -{
 -      float mat[4][4];
 -      float obmat_scale[3];
 -
 -      lamp->lay = lay;
 -      lamp->hide = hide;
 -
 -      normalize_m4_m4_ex(mat, obmat, obmat_scale);
 -
 -      copy_v3_v3(lamp->vec, mat[2]);
 -      copy_v3_v3(lamp->co, mat[3]);
 -      copy_m4_m4(lamp->obmat, mat);
 -      invert_m4_m4(lamp->imat, mat);
 -
 -      if (lamp->type == LA_SPOT) {
 -              /* update spotlamp scale on X and Y axis */
 -              lamp->spotvec[0] = obmat_scale[0] / obmat_scale[2];
 -              lamp->spotvec[1] = obmat_scale[1] / obmat_scale[2];
 -      }
 -
 -      if (GPU_lamp_has_shadow_buffer(lamp)) {
 -              /* makeshadowbuf */
 -              gpu_lamp_calc_winmat(lamp);
 -      }
 -}
 -
 -void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy)
 -{
 -      lamp->energy = energy;
 -      if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
 -
 -      lamp->col[0] = r;
 -      lamp->col[1] = g;
 -      lamp->col[2] = b;
 -}
 -
 -void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2,
 -                              float coeff_const, float coeff_lin, float coeff_quad)
 -{
 -      lamp->dist = distance;
 -      lamp->att1 = att1;
 -      lamp->att2 = att2;
 -      lamp->coeff_const = coeff_const;
 -      lamp->coeff_lin = coeff_lin;
 -      lamp->coeff_quad = coeff_quad;
 -}
 -
 -void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend)
 -{
 -      lamp->spotsi = cosf(spotsize * 0.5f);
 -      lamp->spotbl = (1.0f - lamp->spotsi) * spotblend;
 -}
 -
 -static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp)
 -{
 -      lamp->scene = scene;
 -      lamp->ob = ob;
 -      lamp->par = par;
 -      lamp->la = la;
 -
 -      /* add_render_lamp */
 -      lamp->mode = la->mode;
 -      lamp->type = la->type;
 -
 -      lamp->energy = la->energy;
 -      if (lamp->mode & LA_NEG) lamp->energy = -lamp->energy;
 -
 -      lamp->col[0] = la->r;
 -      lamp->col[1] = la->g;
 -      lamp->col[2] = la->b;
 -
 -      GPU_lamp_update(lamp, ob->lay, (ob->restrictflag & OB_RESTRICT_RENDER), ob->obmat);
 -
 -      lamp->spotsi = la->spotsize;
 -      if (lamp->mode & LA_HALO)
 -              if (lamp->spotsi > DEG2RADF(170.0f))
 -                      lamp->spotsi = DEG2RADF(170.0f);
 -      lamp->spotsi = cosf(lamp->spotsi * 0.5f);
 -      lamp->spotbl = (1.0f - lamp->spotsi) * la->spotblend;
 -      lamp->k = la->k;
 -
 -      lamp->dist = la->dist;
 -      lamp->falloff_type = la->falloff_type;
 -      lamp->att1 = la->att1;
 -      lamp->att2 = la->att2;
 -      lamp->coeff_const = la->coeff_const;
 -      lamp->coeff_lin = la->coeff_lin;
 -      lamp->coeff_quad = la->coeff_quad;
 -      lamp->curfalloff = la->curfalloff;
 -
 -      /* initshadowbuf */
 -      lamp->bias = 0.02f * la->bias;
 -      lamp->size = la->bufsize;
 -      lamp->d = la->clipsta;
 -      lamp->clipend = la->clipend;
 -
 -      /* arbitrary correction for the fact we do no soft transition */
 -      lamp->bias *= 0.25f;
 -}
 -
 -static void gpu_lamp_shadow_free(GPULamp *lamp)
 -{
 -      if (lamp->tex) {
 -              GPU_texture_free(lamp->tex);
 -              lamp->tex = NULL;
 -      }
 -      if (lamp->depthtex) {
 -              GPU_texture_free(lamp->depthtex);
 -              lamp->depthtex = NULL;
 -      }
 -      if (lamp->fb) {
 -              GPU_framebuffer_free(lamp->fb);
 -              lamp->fb = NULL;
 -      }
 -      if (lamp->blurtex) {
 -              GPU_texture_free(lamp->blurtex);
 -              lamp->blurtex = NULL;
 -      }
 -      if (lamp->blurfb) {
 -              GPU_framebuffer_free(lamp->blurfb);
 -              lamp->blurfb = NULL;
 -      }
 -}
 -
 -GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par)
 -{
 -      Lamp *la;
 -      GPULamp *lamp;
 -      LinkData *link;
 -
 -      for (link = ob->gpulamp.first; link; link = link->next) {
 -              lamp = (GPULamp *)link->data;
 -
 -              if (lamp->par == par && lamp->scene == scene)
 -                      return link->data;
 -      }
 -
 -      lamp = MEM_callocN(sizeof(GPULamp), "GPULamp");
 -
 -      link = MEM_callocN(sizeof(LinkData), "GPULampLink");
 -      link->data = lamp;
 -      BLI_addtail(&ob->gpulamp, link);
 -
 -      la = ob->data;
 -      gpu_lamp_from_blender(scene, ob, par, la, lamp);
 -
 -      if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) ||
 -          (la->type == LA_SUN && (la->mode & LA_SHAD_RAY)))
 -      {
 -              /* opengl */
 -              lamp->fb = GPU_framebuffer_create();
 -              if (!lamp->fb) {
 -                      gpu_lamp_shadow_free(lamp);
 -                      return lamp;
 -              }
 -
 -              if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
 -                      /* Shadow depth map */
 -                      lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, NULL);
 -                      if (!lamp->depthtex) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -              
 -                      if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -
 -                      /* Shadow color map */
 -                      lamp->tex = GPU_texture_create_vsm_shadow_map(lamp->size, NULL);
 -                      if (!lamp->tex) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -
 -                      if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -
 -                      if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;                            
 -                      }
 -                      
 -                      /* FBO and texture for blurring */
 -                      lamp->blurfb = GPU_framebuffer_create();
 -                      if (!lamp->blurfb) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -
 -                      lamp->blurtex = GPU_texture_create_vsm_shadow_map(lamp->size * 0.5, NULL);
 -                      if (!lamp->blurtex) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -              
 -                      if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, NULL)) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -                      
 -                      /* we need to properly bind to test for completeness */
 -                      GPU_texture_bind_as_framebuffer(lamp->blurtex);
 -                      
 -                      if (!GPU_framebuffer_check_valid(lamp->blurfb, NULL)) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -                      
 -                      GPU_framebuffer_texture_unbind(lamp->blurfb, lamp->blurtex);
 -              }
 -              else {
 -                      lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL);
 -                      if (!lamp->tex) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -
 -                      if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;
 -                      }
 -                      
 -                      if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) {
 -                              gpu_lamp_shadow_free(lamp);
 -                              return lamp;                            
 -                      }                                               
 -              }
 -
 -              GPU_framebuffer_restore();
 -
 -              lamp->shadow_color[0] = la->shdwr;
 -              lamp->shadow_color[1] = la->shdwg;
 -              lamp->shadow_color[2] = la->shdwb;
 -      }
 -      else {
 -              lamp->shadow_color[0] = 1.0;
 -              lamp->shadow_color[1] = 1.0;
 -              lamp->shadow_color[2] = 1.0;
 -      }
 -
 -      return lamp;
 -}
 -
 -void GPU_lamp_free(Object *ob)
 -{
 -      GPULamp *lamp;
 -      LinkData *link;
 -      LinkData *nlink;
 -      Material *ma;
 -
 -      for (link = ob->gpulamp.first; link; link = link->next) {
 -              lamp = link->data;
 -
 -              while (lamp->materials.first) {
 -                      nlink = lamp->materials.first;
 -                      ma = nlink->data;
 -                      BLI_freelinkN(&lamp->materials, nlink);
 -
 -                      if (ma->gpumaterial.first)
 -                              GPU_material_free(&ma->gpumaterial);
 -              }
 -
 -              gpu_lamp_shadow_free(lamp);
 -
 -              MEM_freeN(lamp);
 -      }
 -
 -      BLI_freelistN(&ob->gpulamp);
 -}
 -
 -bool GPU_lamp_has_shadow_buffer(GPULamp *lamp)
 -{
 -      return (!(lamp->scene->gm.flag & GAME_GLSL_NO_SHADOWS) &&
 -              !(lamp->scene->gm.flag & GAME_GLSL_NO_LIGHTS) &&
 -              lamp->tex && lamp->fb);
 -}
 -
 -void GPU_lamp_update_buffer_mats(GPULamp *lamp)
 -{
 -      float rangemat[4][4], persmat[4][4];
 -
 -      /* initshadowbuf */
 -      invert_m4_m4(lamp->viewmat, lamp->obmat);
 -      normalize_v3(lamp->viewmat[0]);
 -      normalize_v3(lamp->viewmat[1]);
 -      normalize_v3(lamp->viewmat[2]);
 -
 -      /* makeshadowbuf */
 -      mul_m4_m4m4(persmat, lamp->winmat, lamp->viewmat);
 -
 -      /* opengl depth buffer is range 0.0..1.0 instead of -1.0..1.0 in blender */
 -      unit_m4(rangemat);
 -      rangemat[0][0] = 0.5f;
 -      rangemat[1][1] = 0.5f;
 -      rangemat[2][2] = 0.5f;
 -      rangemat[3][0] = 0.5f;
 -      rangemat[3][1] = 0.5f;
 -      rangemat[3][2] = 0.5f;
 -
 -      mul_m4_m4m4(lamp->persmat, rangemat, persmat);
 -}
 -
 -void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsize, float winmat[4][4])
 -{
 -      GPU_lamp_update_buffer_mats(lamp);
 -
 -      /* opengl */
 -      glDisable(GL_SCISSOR_TEST);
 -      GPU_texture_bind_as_framebuffer(lamp->tex);
 -      if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE)
 -              GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE));
 -
 -      /* set matrices */
 -      copy_m4_m4(viewmat, lamp->viewmat);
 -      copy_m4_m4(winmat, lamp->winmat);
 -      *winsize = lamp->size;
 -}
 -
 -void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp)
 -{
 -      if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) {
 -              GPU_shader_unbind();
 -              GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex);
 -      }
 -
 -      GPU_framebuffer_texture_unbind(lamp->fb, lamp->tex);
 -      GPU_framebuffer_restore();
 -      glEnable(GL_SCISSOR_TEST);
 -}
 -
 -int GPU_lamp_shadow_buffer_type(GPULamp *lamp)
 -{
 -      return lamp->la->shadowmap_type;
 -}
 -
 -int GPU_lamp_shadow_bind_code(GPULamp *lamp)
 -{
 -      return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1;
 -}
 -
 -float *GPU_lamp_dynpersmat(GPULamp *lamp)
 -{
 -      return &lamp->dynpersmat[0][0];
 -}
 -
 -int GPU_lamp_shadow_layer(GPULamp *lamp)
 -{
 -      if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW)))
 -              return lamp->lay;
 -      else
 -              return -1;
 -}
 -
  GPUNodeLink *GPU_lamp_get_data(
          GPUMaterial *mat, GPULamp *lamp,
          GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy)
  
        /* ensure shadow buffer and lamp textures will be updated */
        add_user_list(&mat->lamps, lamp);
 -      add_user_list(&lamp->materials, mat->ma);
  
        return visifac;
  }
@@@ -2730,7 -2728,6 +2730,7 @@@ GPUShaderExport *GPU_shader_export(stru
                                                break;
  
                                        case GPU_NONE:
 +                                      case GPU_TEX3D:
                                        case GPU_TEXCUBE:
                                        case GPU_FLOAT:
                                        case GPU_VEC2:
                                        case GPU_VEC4:
                                        case GPU_MAT3:
                                        case GPU_MAT4:
 +                                      case GPU_CLOSURE:
                                        case GPU_ATTRIB:
                                                break;
                                }
                                                break;
  
                                        case GPU_NONE:
 +                                      case GPU_CLOSURE:
                                        case GPU_TEX2D:
 +                                      case GPU_TEX3D:
                                        case GPU_TEXCUBE:
                                        case GPU_SHADOW2D:
                                        case GPU_ATTRIB:
index 0a97cdc693a0e88b3dc652711df088d97e8c079f,1f5ffbdcc7e25df60f0e3147bd85b02876dc04c5..7acd9aa1fd579c5a98521a243b6700bbc572f377
@@@ -1,57 -1,11 +1,57 @@@
 +
 +uniform mat4 ModelViewMatrix;
 +#ifndef EEVEE_ENGINE
 +uniform mat4 ProjectionMatrix;
 +uniform mat4 ViewMatrixInverse;
 +uniform mat4 ViewMatrix;
 +#endif
 +uniform mat4 ModelMatrix;
 +uniform mat4 ModelMatrixInverse;
 +uniform mat4 ModelViewMatrixInverse;
 +uniform mat4 ProjectionMatrixInverse;
 +uniform mat3 NormalMatrix;
 +uniform vec4 CameraTexCoFactors;
 +
 +/* Old glsl mode compat. */
 +
 +#ifndef CLOSURE_DEFAULT
 +
 +struct Closure {
 +      vec3 radiance;
 +      float opacity;
 +};
 +
 +#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0)
 +
 +Closure closure_mix(Closure cl1, Closure cl2, float fac)
 +{
 +      Closure cl;
 +      cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
 +      cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
 +      return cl;
 +}
 +
 +Closure closure_add(Closure cl1, Closure cl2)
 +{
 +      Closure cl;
 +      cl.radiance = cl1.radiance + cl2.radiance;
 +      cl.opacity = cl1.opacity + cl2.opacity;
 +      return cl;
 +}
 +
 +Closure nodetree_exec(void); /* Prototype */
 +
 +#endif /* CLOSURE_DEFAULT */
 +
 +
  /* Converters */
  
  float convert_rgba_to_float(vec4 color)
  {
  #ifdef USE_NEW_SHADING
 -      return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
 +      return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
  #else
 -      return (color.r + color.g + color.b) / 3.0;
 +      return (color.r + color.g + color.b) * 0.333333;
  #endif
  }
  
@@@ -99,7 -53,7 +99,7 @@@ void rgb_to_hsv(vec4 rgb, out vec4 outc
                h = 0.0;
        }
        else {
 -              c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta;
 +              c = (vec3(cmax) - rgb.xyz) / cdelta;
  
                if (rgb.x == cmax) h = c[2] - c[1];
                else if (rgb.y == cmax) h = 2.0 + c[0] -  c[2];
@@@ -201,18 -155,15 +201,18 @@@ void color_to_blender_normal_new_shadin
        normal.y = -2.0 * ((color.g) - 0.5);
        normal.z = -2.0 * ((color.b) - 0.5);
  }
 -
 +#ifndef M_PI
  #define M_PI 3.14159265358979323846
 -#define M_1_PI 0.31830988618379069
 +#endif
 +#ifndef M_1_PI
 +#define M_1_PI 0.318309886183790671538
 +#endif
  
  /*********** SHADER NODES ***************/
  
  void vcol_attribute(vec4 attvcol, out vec4 vcol)
  {
 -      vcol = vec4(attvcol.x, attvcol.y, attvcol.z, 1.0);
 +      vcol = vec4(attvcol.xyz, 1.0);
  }
  
  void uv_attribute(vec2 attuv, out vec3 uv)
@@@ -226,7 -177,7 +226,7 @@@ void geom
          out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
  {
        local = co;
 -      view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
 +      view = (ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
        global = (viewinvmat * vec4(local, 1.0)).xyz;
        orco = attorco;
        uv_attribute(attuv, uv);
  }
  
  void particle_info(
-         vec4 sprops, vec3 loc, vec3 vel, vec3 avel,
-         out float random, out float age, out float life_time, out vec3 location,
+         vec4 sprops, vec4 loc, vec3 vel, vec3 avel,
+         out float index, out float random, out float age,
+         out float life_time, out vec3 location,
          out float size, out vec3 velocity, out vec3 angular_velocity)
  {
-       random = sprops.x;
+       index = sprops.x;
+       random = loc.w;
        age = sprops.y;
        life_time = sprops.z;
        size = sprops.w;
  
-       location = loc;
+       location = loc.xyz;
        velocity = vel;
        angular_velocity = avel;
  }
@@@ -468,13 -421,13 +470,13 @@@ void squeeze(float val, float width, fl
  void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
  {
        outvec = v1 + v2;
 -      outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
 +      outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
  }
  
  void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
  {
        outvec = v1 - v2;
 -      outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
 +      outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
  }
  
  void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@@ -490,7 -443,7 +492,7 @@@ void vec_math_mix(float strength, vec3 
  
  void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
  {
 -      outvec = vec3(0, 0, 0);
 +      outvec = vec3(0);
        outval = dot(v1, v2);
  }
  
@@@ -532,9 -485,9 +534,9 @@@ void normal_new_shading(vec3 dir, vec3 
  
  void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
  {
 -      outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
 -      outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
 -      outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
 +      outvec.x = texture(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
 +      outvec.y = texture(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
 +      outvec.z = texture(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
  
        if (fac != 1.0)
                outvec = (outvec * fac) + (vec * (1.0 - fac));
  
  void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol)
  {
 -      outcol.r = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.r, 0.0)).a, 0.0)).r;
 -      outcol.g = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.g, 0.0)).a, 0.0)).g;
 -      outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
 +      outcol.r = texture(curvemap, vec2(texture(curvemap, vec2(col.r, 0.0)).a, 0.0)).r;
 +      outcol.g = texture(curvemap, vec2(texture(curvemap, vec2(col.g, 0.0)).a, 0.0)).g;
 +      outcol.b = texture(curvemap, vec2(texture(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
  
        if (fac != 1.0)
                outcol = (outcol * fac) + (col * (1.0 - fac));
@@@ -865,23 -818,22 +867,23 @@@ void mix_linear(float fac, vec4 col1, v
  
  void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
  {
 -      outcol = texture2D(colormap, vec2(fac, 0.0));
 +      outcol = texture(colormap, vec2(fac, 0.0));
        outalpha = outcol.a;
  }
  
  void rgbtobw(vec4 color, out float outval)
  {
  #ifdef USE_NEW_SHADING
 -      outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
 +      vec3 factors = vec3(0.2126, 0.7152, 0.0722);
  #else
 -      outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */
 +      vec3 factors = vec3(0.35, 0.45, 0.2); /* keep these factors in sync with texture.h:RGBTOBW */
  #endif
 +      outval = dot(color.rgb, factors);
  }
  
  void invert(float fac, vec4 col, out vec4 outcol)
  {
 -      outcol.xyz = mix(col.xyz, vec3(1.0, 1.0, 1.0) - col.xyz, fac);
 +      outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac);
        outcol.w = col.w;
  }
  
@@@ -966,12 -918,12 +968,12 @@@ void texture_flip_blend(vec3 vec, out v
  
  void texture_blend_lin(vec3 vec, out float outval)
  {
 -      outval = (1.0 + vec.x) / 2.0;
 +      outval = (1.0 + vec.x) * 0.5;
  }
  
  void texture_blend_quad(vec3 vec, out float outval)
  {
 -      outval = max((1.0 + vec.x) / 2.0, 0.0);
 +      outval = max((1.0 + vec.x) * 0.5, 0.0);
        outval *= outval;
  }
  
@@@ -982,12 -934,12 +984,12 @@@ void texture_wood_sin(vec3 vec, out flo
  
        value = wi;
        color = vec4(wi, wi, wi, 1.0);
 -      normal = vec3(0.0, 0.0, 0.0);
 +      normal = vec3(0.0);
  }
  
  void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal)
  {
 -      color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5);
 +      color = texture(ima, (vec.xy + vec2(1.0)) * 0.5);
        value = color.a;
  
        normal.x = 2.0 * (color.r - 0.5);
@@@ -1327,7 -1279,11 +1329,7 @@@ void mtex_har_divide(float har, out flo
  
  void mtex_har_multiply_clamp(float har, out float outhar)
  {
 -      har *= 128.0;
 -
 -      if (har < 1.0) outhar = 1.0;
 -      else if (har > 511.0) outhar = 511.0;
 -      else outhar = har;
 +      outhar = clamp(har * 128.0, 1.0, 511.0);
  }
  
  void mtex_alpha_from_col(vec4 col, out float alpha)
@@@ -1396,14 -1352,14 +1398,14 @@@ vec3 mtex_2d_mapping(vec3 vec
  
  void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
  {
 -      color = textureCube(ima, co);
 +      color = texture(ima, co);
        value = 1.0;
  }
  
  void mtex_cube_map_refl_from_refldir(
          samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color)
  {
 -        color = textureCube(ima, reflecteddirection);
 +        color = texture(ima, reflecteddirection);
          value = color.a;
  }
  
@@@ -1414,13 -1370,13 +1416,13 @@@ void mtex_cube_map_refl
        vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0));
        vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix));
        vec3 reflecteddirection = reflect(viewdirection, normaldirection);
 -      color = textureCube(ima, reflecteddirection);
 +      color = texture(ima, reflecteddirection);
        value = 1.0;
  }
  
  void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color)
  {
 -      color = texture2D(ima, texco.xy);
 +      color = texture(ima, texco.xy);
        value = 1.0;
  }
  
@@@ -1431,7 -1387,7 +1433,7 @@@ void mtex_normal(vec3 texco, sampler2D 
        // It needs to be done because in Blender
        // the normal used points inward.
        // Should this ever change this negate must be removed.
 -      vec4 color = texture2D(ima, texco.xy);
 +      vec4 color = texture(ima, texco.xy);
        normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
  }
  
@@@ -1459,8 -1415,8 +1461,8 @@@ void mtex_bump_init_objspace
          out float fPrevMagnitude_out, out vec3 vNacc_out,
          out vec3 vR1, out vec3 vR2, out float fDet)
  {
 -      mat3 obj2view = to_mat3(gl_ModelViewMatrix);
 -      mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse);
 +      mat3 obj2view = to_mat3(ModelViewMatrix);
 +      mat3 view2obj = to_mat3(ModelViewMatrixInverse);
  
        vec3 vSigmaS = view2obj * dFdx(surf_pos);
        vec3 vSigmaT = view2obj * dFdy(surf_pos);
@@@ -1527,9 -1483,9 +1529,9 @@@ void mtex_bump_tap3
        vec2 STul = texco.xy + dFdy(texco.xy);
  
        float Hll, Hlr, Hul;
 -      rgbtobw(texture2D(ima, STll), Hll);
 -      rgbtobw(texture2D(ima, STlr), Hlr);
 -      rgbtobw(texture2D(ima, STul), Hul);
 +      rgbtobw(texture(ima, STll), Hll);
 +      rgbtobw(texture(ima, STlr), Hlr);
 +      rgbtobw(texture(ima, STul), Hul);
  
        dBs = hScale * (Hlr - Hll);
        dBt = hScale * (Hul - Hll);
@@@ -1554,10 -1510,10 +1556,10 @@@ void mtex_bump_bicubic
        vec2 STd = texco.xy - 0.5 * TexDy;
        vec2 STu = texco.xy + 0.5 * TexDy;
  
 -      rgbtobw(texture2D(ima, STl), Hl);
 -      rgbtobw(texture2D(ima, STr), Hr);
 -      rgbtobw(texture2D(ima, STd), Hd);
 -      rgbtobw(texture2D(ima, STu), Hu);
 +      rgbtobw(texture(ima, STl), Hl);
 +      rgbtobw(texture(ima, STr), Hr);
 +      rgbtobw(texture(ima, STd), Hd);
 +      rgbtobw(texture(ima, STu), Hu);
  
        vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
        float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
@@@ -1643,11 -1599,11 +1645,11 @@@ void mtex_bump_tap5
        vec2 STu = texco.xy + 0.5 * TexDy;
  
        float Hc, Hl, Hr, Hd, Hu;
 -      rgbtobw(texture2D(ima, STc), Hc);
 -      rgbtobw(texture2D(ima, STl), Hl);
 -      rgbtobw(texture2D(ima, STr), Hr);
 -      rgbtobw(texture2D(ima, STd), Hd);
 -      rgbtobw(texture2D(ima, STu), Hu);
 +      rgbtobw(texture(ima, STc), Hc);
 +      rgbtobw(texture(ima, STl), Hl);
 +      rgbtobw(texture(ima, STr), Hr);
 +      rgbtobw(texture(ima, STd), Hd);
 +      rgbtobw(texture(ima, STu), Hu);
  
        dBs = hScale * (Hr - Hl);
        dBt = hScale * (Hu - Hd);
@@@ -1664,7 -1620,7 +1666,7 @@@ void mtex_bump_deriv
        // this variant using a derivative map is described here
        // http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
        vec2 dim = vec2(ima_x, ima_y);
 -      vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0);
 +      vec2 dBduv = hScale * dim * (2.0 * texture(ima, texco.xy).xy - 1.0);
  
        dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y;
        dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y;
@@@ -1716,7 -1672,7 +1718,7 @@@ void mtex_nspace_world(mat4 viewmat, ve
  
  void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
  {
 -      outnormal = normalize(gl_NormalMatrix * texnormal);
 +      outnormal = normalize(NormalMatrix * texnormal);
  }
  
  void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
@@@ -1773,7 -1729,7 +1775,7 @@@ void lamp_falloff_invcoefficients(floa
  
  void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
  {
 -      visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x;
 +      visifac = texture(curvemap, vec2(dist / lampdist, 0.0)).x;
  }
  
  void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac)
@@@ -1840,7 -1796,7 +1842,7 @@@ void lamp_visibility_clamp(float visifa
  void world_paper_view(vec3 vec, out vec3 outvec)
  {
        vec3 nvec = normalize(vec);
 -      outvec = (gl_ProjectionMatrix[3][3] == 0.0) ? vec3(nvec.x, 0.0, nvec.y) : vec3(0.0, 0.0, -1.0);
 +      outvec = (ProjectionMatrix[3][3] == 0.0) ? vec3(nvec.x, 0.0, nvec.y) : vec3(0.0, 0.0, -1.0);
  }
  
  void world_zen_mapping(vec3 view, float zenup, float zendown, out float zenfac)
@@@ -1874,7 -1830,7 +1876,7 @@@ void world_blend(vec3 vec, out float bl
  void shade_view(vec3 co, out vec3 view)
  {
        /* handle perspective/orthographic */
 -      view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
 +      view = (ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
  }
  
  void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn)
@@@ -2066,7 -2022,7 +2068,7 @@@ void shade_add_to_diffuse(float i, vec
        if (i > 0.0)
                outcol = i * lampcol * col;
        else
 -              outcol = vec3(0.0, 0.0, 0.0);
 +              outcol = vec3(0.0);
  }
  
  void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float visifac, out float t)
@@@ -2223,12 -2179,12 +2225,12 @@@ void shade_madd(vec4 col, vec4 col1, ve
  
  void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
  {
 -      outcol = col1 + max(col2, vec4(0.0, 0.0, 0.0, 0.0));
 +      outcol = col1 + max(col2, vec4(0.0));
  }
  
  void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
  {
 -      outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
 +      outcol = col + max(col1 * col2, vec4(0.0));
  }
  
  void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
@@@ -2265,7 -2221,7 +2267,7 @@@ void shade_obcolor(vec4 col, vec4 obcol
  
  void ramp_rgbtobw(vec3 color, out float outval)
  {
 -      outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12;
 +      outval = dot(color, vec3(0.3, 0.58, 0.12));
  }
  
  void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
@@@ -2301,12 -2257,10 +2303,12 @@@ void test_shadowbuf
                //float bias = (1.5 - inp*inp)*shadowbias;
                co.z -= shadowbias * co.w;
  
 -              if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0)
 -                      result = shadow2DProj(shadowmap, co).x;
 -              else
 +              if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
 +                      result = textureProj(shadowmap, co);
 +              }
 +              else {
                        result = 1.0;
 +              }
        }
  }
  
@@@ -2320,7 -2274,7 +2322,7 @@@ void test_shadowbuf_vsm
        else {
                vec4 co = shadowpersmat * vec4(rco, 1.0);
                if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
 -                      vec2 moments = texture2DProj(shadowmap, co).rg;
 +                      vec2 moments = textureProj(shadowmap, co).rg;
                        float dist = co.z / co.w;
                        float p = 0.0;
  
@@@ -2379,7 -2333,7 +2381,7 @@@ void shade_light_texture(vec3 rco, samp
  
        vec4 co = shadowpersmat * vec4(rco, 1.0);
  
 -      result = texture2DProj(cookie, co);
 +      result = textureProj(cookie, co);
  }
  
  void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
@@@ -2394,7 -2348,7 +2396,7 @@@ void shade_mist_factor
        if (enable == 1.0) {
                float fac, zcor;
  
 -              zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
 +              zcor = (ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
  
                fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
                if (misttype == 0.0) fac *= fac;
@@@ -2469,15 -2423,7 +2471,15 @@@ float hypot(float x, float y
  
  void generated_from_orco(vec3 orco, out vec3 generated)
  {
 -      generated = orco * 0.5 + vec3(0.5);
 +#ifdef VOLUMETRICS
 +#ifdef MESH_SHADER
 +      generated = volumeObjectLocalCoord;
 +#else
 +      generated = worldPosition;
 +#endif
 +#else
 +      generated = orco;
 +#endif
  }
  
  int floor_to_int(float x)
@@@ -2490,6 -2436,7 +2492,6 @@@ int quick_floor(float x
        return int(x) - ((x < 0) ? 1 : 0);
  }
  
 -#ifdef BIT_OPERATIONS
  float integer_noise(int n)
  {
        int nn;
@@@ -2553,6 -2500,7 +2555,6 @@@ vec3 cellnoise_color(vec3 p
  
        return vec3(r, g, b);
  }
 -#endif  // BIT_OPERATIONS
  
  float floorfrac(float x, out int i)
  {
@@@ -2614,107 -2562,41 +2616,107 @@@ vec3 rotate_vector(vec3 p, vec3 n, floa
               );
  }
  
 +void prepare_tangent(
 +        float anisotropic, float anisotropic_rotation, float roughness, vec3 N, vec3 T,
 +        out vec3 X, out vec3 Y, out float ax, out float ay)
 +{
 +      /* rotate tangent */
 +      if (anisotropic_rotation != 0.0) {
 +              T = rotate_vector(T, N, anisotropic_rotation * 2.0 * M_PI);
 +      }
 +
 +      Y = normalize(cross(T, N));
 +
 +      float aspect = sqrt(1.0 - anisotropic * 0.9);
 +      float a = sqr(roughness);
 +      ax = max(0.001, a / aspect);
 +      ay = max(0.001, a * aspect);
 +}
 +
 +void convert_metallic_to_specular(vec3 basecol, float metallic, float specular_fac, out vec3 diffuse, out vec3 f0)
 +{
 +      vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
 +      diffuse = mix(basecol, vec3(0.0), metallic);
 +      f0 = mix(dielectric, basecol, metallic);
 +}
 +
 +void convert_metallic_to_specular_tinted(
 +        vec3 basecol, float metallic, float specular_fac, float specular_tint,
 +        out vec3 diffuse, out vec3 f0)
 +{
 +      vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
 +      float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
 +      vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
 +      f0 = mix(dielectric * mix(vec3(1.0), tint, specular_tint), basecol, metallic);
 +      diffuse = mix(basecol, vec3(0.0), metallic);
 +}
  
  /*********** NEW SHADER NODES ***************/
  
  #define NUM_LIGHTS 3
  
 -/* bsdfs */
 +struct glLight {
 +      vec4 position;
 +      vec4 diffuse;
 +      vec4 specular;
 +      vec4 halfVector;
 +};
  
 -void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
 -{
 +layout(std140) uniform lightSource {
 +      glLight glLightSource[NUM_LIGHTS];
 +};
 +
 +#ifndef VOLUMETRICS
 +/* bsdfs */
 +void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
 +{
 +#ifdef EEVEE_ENGINE
 +      vec3 vN = normalize(mat3(ViewMatrix) * N);
 +      result = CLOSURE_DEFAULT;
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +      eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
 +      result.radiance *= color.rgb;
 +#else
        /* ambient light */
        vec3 L = vec3(0.2);
  
        /* directional lights */
        for (int i = 0; i < NUM_LIGHTS; i++) {
 -              vec3 light_position = gl_LightSource[i].position.xyz;
 -              vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
 +              vec3 light_position = glLightSource[i].position.xyz;
 +              vec3 light_diffuse = glLightSource[i].diffuse.rgb;
  
                float bsdf = max(dot(N, light_position), 0.0);
                L += light_diffuse * bsdf;
        }
  
 -      result = vec4(L * color.rgb, 1.0);
 +      result = Closure(L * color.rgb, 1.0);
 +#endif
  }
  
 -void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
 +void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
  {
 +#ifdef EEVEE_ENGINE
 +      vec3 out_spec, ssr_spec;
 +      roughness = sqrt(roughness);
 +      eevee_closure_glossy(N, vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
 +      vec3 vN = normalize(mat3(ViewMatrix) * N);
 +      result = CLOSURE_DEFAULT;
 +      result.radiance = out_spec * color.rgb;
 +      result.ssr_data = vec4(ssr_spec * color.rgb, roughness);
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +      result.ssr_id = int(ssr_id);
 +#else
        /* ambient light */
        vec3 L = vec3(0.2);
  
 +      direction_transform_m4v3(N, ViewMatrix, N);
 +
        /* directional lights */
        for (int i = 0; i < NUM_LIGHTS; i++) {
 -              vec3 light_position = gl_LightSource[i].position.xyz;
 -              vec3 H = gl_LightSource[i].halfVector.xyz;
 -              vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
 -              vec3 light_specular = gl_LightSource[i].specular.rgb;
 +              vec3 light_position = glLightSource[i].position.xyz;
 +              vec3 H = glLightSource[i].halfVector.xyz;
 +              vec3 light_diffuse = glLightSource[i].diffuse.rgb;
 +              vec3 light_specular = glLightSource[i].specular.rgb;
  
                /* we mix in some diffuse so low roughness still shows up */
                float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
                L += light_specular * bsdf;
        }
  
 -      result = vec4(L * color.rgb, 1.0);
 +      result = Closure(L * color.rgb, 1.0);
 +#endif
  }
  
  void node_bsdf_anisotropic(
          vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
 -        out vec4 result)
 +        out Closure result)
  {
        node_bsdf_diffuse(color, 0.0, N, result);
  }
  
 -void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
 -{
 +void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result)
 +{
 +#ifdef EEVEE_ENGINE
 +      vec3 out_spec, out_refr, ssr_spec;
 +      roughness = sqrt(roughness);
 +      vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb : color.rgb; /* Simulate 2 transmission event */
 +      eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
 +      out_refr *= refr_color;
 +      out_spec *= color.rgb;
 +      float fresnel = F_eta(ior, dot(N, cameraVec));
 +      vec3 vN = normalize(mat3(ViewMatrix) * N);
 +      result = CLOSURE_DEFAULT;
 +      result.radiance = mix(out_refr, out_spec, fresnel);
 +      result.ssr_data = vec4(ssr_spec * color.rgb * fresnel, roughness);
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +      result.ssr_id = int(ssr_id);
 +#else
        node_bsdf_diffuse(color, 0.0, N, result);
 +#endif
  }
  
 -void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 result)
 +void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
  {
        node_bsdf_diffuse(color, 0.0, N, result);
  }
  
 +#ifndef EEVEE_ENGINE
  void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
        float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
 -      float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
 +      float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
  {
 +      vec3 X, Y;
 +      float ax, ay;
 +      prepare_tangent(anisotropic, anisotropic_rotation, roughness, N, T, X, Y, ax, ay);
 +
        /* ambient light */
        // TODO: set ambient light to an appropriate value
        vec3 L = mix(0.1, 0.03, metallic) * mix(base_color.rgb, subsurface_color.rgb, subsurface * (1.0 - metallic));
        float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
  
        /* set the viewing vector */
 -      vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0);
 -
 -      /* get the tangent */
 -      vec3 Tangent = T;
 -      if (T == vec3(0.0)) {
 -              // if no tangent is set, use a default tangent
 -              if(N.x != N.y || N.x != N.z) {
 -                      Tangent = vec3(N.z-N.y, N.x-N.z, N.y-N.x);  // (1,1,1) x N
 -              }
 -              else {
 -                      Tangent = vec3(N.z-N.y, N.x+N.z, -N.y-N.x);  // (-1,1,1) x N
 -              }
 -      }
 -
 -      /* rotate tangent */
 -      if (anisotropic_rotation != 0.0) {
 -              Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI);
 -      }
 -
 -      /* calculate the tangent and bitangent */
 -      vec3 Y = normalize(cross(N, Tangent));
 -      vec3 X = cross(Y, N);
 +      vec3 V = (ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0);
  
        /* fresnel normalization parameters */
        float F0 = fresnel_dielectric_0(eta);
  
        /* directional lights */
        for (int i = 0; i < NUM_LIGHTS; i++) {
 -              vec3 light_position_world = gl_LightSource[i].position.xyz;
 +              vec3 light_position_world = glLightSource[i].position.xyz;
                vec3 light_position = normalize(light_position_world);
  
                vec3 H = normalize(light_position + V);
  
 -              vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
 -              vec3 light_specular = gl_LightSource[i].specular.rgb;
 +              vec3 light_diffuse = glLightSource[i].diffuse.rgb;
 +              vec3 light_specular = glLightSource[i].specular.rgb;
  
                float NdotL = dot(N, light_position);
                float NdotV = dot(N, V);
                if (NdotL >= 0.0 && NdotV >= 0.0) {
                        float NdotH = dot(N, H);
  
 -                      float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx.
 +                      float Cdlum = dot(base_color.rgb, vec3(0.3, 0.6, 0.1)); // luminance approx.
  
                        vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
                        vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic);
                        float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5);
  
                        // specular
 -                      float aspect = sqrt(1.0 - anisotropic * 0.9);
 -                      float a = sqr(roughness);
 -                      float ax = max(0.001, a / aspect);
 -                      float ay = max(0.001, a * aspect);
                        float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a);
                        float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm;
                        vec3 Fs = mix(Cspec0, vec3(1.0), FH);
                L += diffuse_and_specular_bsdf + clearcoat_bsdf;
        }
  
 -      result = vec4(L, 1.0);
 +      result = Closure(L, 1.0);
  }
 +#endif
  
 -void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
 +void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
 +      float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
 +      float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
 +      float sss_id, vec3 sss_scale, out Closure result)
  {
 -      node_bsdf_diffuse(color, 0.0, N, result);
 +#ifdef EEVEE_ENGINE
 +      metallic = saturate(metallic);
 +      transmission = saturate(transmission);
 +
 +      vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
 +      convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
 +
 +      transmission *= 1.0 - metallic;
 +      subsurface *= 1.0 - metallic;
 +
 +      clearcoat *= 0.25;
 +      clearcoat *= 1.0 - transmission;
 +
 +#ifdef USE_SSS
 +      diffuse = mix(diffuse, vec3(0.0), subsurface);
 +#else
 +      diffuse = mix(diffuse, subsurface_color.rgb, subsurface);
 +#endif
 +      f0 = mix(f0, vec3(1.0), transmission);
 +
 +      float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0));
 +      eevee_closure_principled(N, diffuse, f0, int(ssr_id), roughness,
 +                               CN, clearcoat, clearcoat_roughness, 1.0, sss_scalef, ior,
 +                               out_diff, out_trans, out_spec, out_refr, ssr_spec);
 +
 +      vec3 refr_color = base_color.rgb;
 +      refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission event */
 +
 +      float fresnel = F_eta(ior, dot(N, cameraVec));
 +      vec3 refr_spec_color = base_color.rgb * fresnel;
 +      /* This bit maybe innacurate. */
 +      out_refr = out_refr * refr_color * (1.0 - fresnel) + out_spec * refr_spec_color;
 +
 +      ssr_spec = mix(ssr_spec, refr_spec_color, transmission);
 +
 +      vec3 vN = normalize(mat3(ViewMatrix) * N);
 +      result = CLOSURE_DEFAULT;
 +      result.radiance = out_spec + out_diff * diffuse;
 +      result.radiance = mix(result.radiance, out_refr, transmission);
 +      result.ssr_data = vec4(ssr_spec, roughness);
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +      result.ssr_id = int(ssr_id);
 +#ifdef USE_SSS
 +      result.sss_data.a = sss_scalef;
 +      result.sss_data.rgb = out_diff + out_trans;
 +#ifdef USE_SSS_ALBEDO
 +      result.sss_albedo.rgb = mix(vec3(0.0), subsurface_color.rgb, subsurface);
 +#else
 +      result.sss_data.rgb *= mix(vec3(0.0), subsurface_color.rgb, subsurface);
 +#endif
 +      result.sss_data.rgb *= (1.0 - transmission);
 +#endif
 +
 +#else
 +      node_bsdf_principled(base_color, subsurface, subsurface_radius, subsurface_color, metallic, specular,
 +              specular_tint, roughness, anisotropic, anisotropic_rotation, sheen, sheen_tint, clearcoat,
 +              clearcoat_roughness, ior, transmission, transmission_roughness, N, CN, T, I, result);
 +#endif
 +}
 +
 +void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
 +{
 +      node_bsdf_diffuse(color, 0.0, -N, result);
  }
  
 -void node_bsdf_transparent(vec4 color, out vec4 result)
 +void node_bsdf_transparent(vec4 color, out Closure result)
  {
        /* this isn't right */
 -      result.r = color.r;
 -      result.g = color.g;
 -      result.b = color.b;
 -      result.a = 0.0;
 +      result = CLOSURE_DEFAULT;
 +      result.radiance = vec3(0.0);
 +      result.opacity = 0.0;
 +#ifdef EEVEE_ENGINE
 +      result.ssr_id = TRANSPARENT_CLOSURE_FLAG;
 +#endif
  }
  
 -void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result)
 +void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
  {
        node_bsdf_diffuse(color, 0.0, N, result);
  }
  
  void node_subsurface_scattering(
 -        vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
 -        out vec4 result)
 -{
 +        vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, float sss_id,
 +        out Closure result)
 +{
 +#if defined(EEVEE_ENGINE) && defined(USE_SSS)
 +      vec3 out_diff, out_trans;
 +      vec3 vN = normalize(mat3(ViewMatrix) * N);
 +      result = CLOSURE_DEFAULT;
 +      result.ssr_data = vec4(0.0);
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +      result.ssr_id = -1;
 +      result.sss_data.a = scale;
 +      eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
 +      result.sss_data.rgb = out_diff + out_trans;
 +#ifdef USE_SSS_ALBEDO
 +      /* Not perfect for texture_blur not exaclty equal to 0.0 or 1.0. */
 +      result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur);
 +      result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur);
 +#else
 +      result.sss_data.rgb *= color.rgb;
 +#endif
 +#else
        node_bsdf_diffuse(color, 0.0, N, result);
 +#endif
  }
  
 -void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result)
 +void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
  {
 -      result = color;
 +#ifdef EEVEE_ENGINE
 +      vec3 out_refr;
 +      color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
 +      roughness = sqrt(roughness);
 +      eevee_closure_refraction(N, roughness, ior, out_refr);
 +      vec3 vN = normalize(mat3(ViewMatrix) * N);
 +      result = CLOSURE_DEFAULT;
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +      result.radiance = out_refr * color.rgb;
 +      result.ssr_id = REFRACT_CLOSURE_FLAG;
 +#else
 +      node_bsdf_diffuse(color, 0.0, N, result);
 +#endif /* EEVEE_ENGINE */
  }
  
 -void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
 +/* Unsupported for now */
 +#ifndef EEVEE_ENGINE
 +void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out Closure result)
  {
 -      node_bsdf_diffuse(color, 0.0, N, result);
 +      result = Closure(color.rgb, color.a);
  }
  
 -void node_ambient_occlusion(vec4 color, out vec4 result)
 +void node_ambient_occlusion(vec4 color, out Closure result)
  {
 -      result = color;
 +      result = Closure(color.rgb, color.a);
  }
 +#endif /* EEVEE_ENGINE */
 +
 +#endif /* VOLUMETRICS */
  
  /* emission */
  
 -void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
 +void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
  {
 -      result = color * strength;
 +#ifndef VOLUMETRICS
 +      color *= strength;
 +#ifdef EEVEE_ENGINE
 +      result = CLOSURE_DEFAULT;
 +      result.radiance = color.rgb;
 +      result.opacity = color.a;
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +#else
 +      result = Closure(color.rgb, color.a);
 +#endif
 +#else
 +      result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0);
 +#endif
  }
  
  /* background */
  
  void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
  {
 -      vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
 -      vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
 +      vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
 +      vec4 co_homogenous = (ProjectionMatrixInverse * v);
  
        vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
 -      worldvec = (gl_ModelViewMatrixInverse * co).xyz;
 +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
 +      worldvec = (ViewMatrixInverse * co).xyz;
 +#else
 +      worldvec = (ModelViewMatrixInverse * co).xyz;
 +#endif
 +}
 +
 +void node_background(vec4 color, float strength, out Closure result)
 +{
 +#ifndef VOLUMETRICS
 +      color *= strength;
 +#ifdef EEVEE_ENGINE
 +      result = CLOSURE_DEFAULT;
 +      result.radiance = color.rgb;
 +      result.opacity = color.a;
 +#else
 +      result = Closure(color.rgb, color.a);
 +#endif
 +#else
 +      result = CLOSURE_DEFAULT;
 +#endif
 +}
 +
 +/* volumes */
 +
 +void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
 +{
 +#ifdef VOLUMETRICS
 +      result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
 +#else
 +      result = CLOSURE_DEFAULT;
 +#endif
  }
  
 -void node_background(vec4 color, float strength, vec3 N, out vec4 result)
 +void node_volume_absorption(vec4 color, float density, out Closure result)
  {
 -      result = color * strength;
 +#ifdef VOLUMETRICS
 +      result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
 +#else
 +      result = CLOSURE_DEFAULT;
 +#endif
  }
  
  /* closures */
  
 -void node_mix_shader(float fac, vec4 shader1, vec4 shader2, out vec4 shader)
 +void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
  {
 -      shader = mix(shader1, shader2, fac);
 +      shader = closure_mix(shader1, shader2, fac);
  }
  
 -void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
 +void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
  {
 -      shader = shader1 + shader2;
 +      shader = closure_add(shader1, shader2);
  }
  
  /* fresnel */
  void node_fresnel(float ior, vec3 N, vec3 I, out float result)
  {
        /* handle perspective/orthographic */
 -      vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
 +      vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
  
        float eta = max(ior, 0.00001);
        result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
@@@ -3102,7 -2836,7 +3104,7 @@@ void node_layer_weight(float blend, vec
  {
        /* fresnel */
        float eta = max(1.0 - blend, 0.00001);
 -      vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
 +      vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
  
        fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
  
@@@ -3132,47 -2866,11 +3134,47 @@@ void node_gamma(vec4 col, float gamma, 
  
  /* geometry */
  
 +void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
 +{
 +#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS)
 +      vec3 cos = volumeObjectLocalCoord;
 +#else
 +      vec3 cos = vec3(0.0);
 +#endif
 +      outvec = texture(tex, cos).aaa;
 +      outcol = vec4(outvec, 1.0);
 +      outf = dot(vec3(1.0 / 3.0), outvec);
 +}
 +
 +void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
 +{
 +#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS)
 +      vec3 cos = volumeObjectLocalCoord;
 +#else
 +      vec3 cos = vec3(0.0);
 +#endif
 +      outvec = texture(tex, cos).rgb;
 +      outcol = vec4(outvec, 1.0);
 +      outf = dot(vec3(1.0 / 3.0), outvec);
 +}
 +
 +void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
 +{
 +#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS)
 +      vec3 cos = volumeObjectLocalCoord;
 +#else
 +      vec3 cos = vec3(0.0);
 +#endif
 +      outvec = texture(tex, cos).rrr;
 +      outcol = vec4(outvec, 1.0);
 +      outf = dot(vec3(1.0 / 3.0), outvec);
 +}
 +
  void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
  {
        outcol = vec4(attr, 1.0);
        outvec = attr;
 -      outf = (attr.x + attr.y + attr.z) / 3.0;
 +      outf =  dot(vec3(1.0 / 3.0), attr);
  }
  
  void node_uvmap(vec3 attr_uv, out vec3 outvec)
        outvec = attr_uv;
  }
  
 +void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
 +{
 +      orco_out = vec3(0.0, (orco_in.z - 0.5) * -0.5, (orco_in.y - 0.5) * 0.5);
 +}
 +
 +void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
 +{
 +      orco_out = vec3((orco_in.z - 0.5) * -0.5, 0.0, (orco_in.x - 0.5) * 0.5);
 +}
 +
 +void tangent_orco_z(vec3 orco_in, out vec3 orco_out)
 +{
 +      orco_out = vec3((orco_in.y - 0.5) * -0.5, (orco_in.x - 0.5) * 0.5, 0.0);
 +}
 +
 +void node_tangentmap(vec4 attr_tangent, mat4 toworld, out vec3 tangent)
 +{
 +      tangent = (toworld * vec4(attr_tangent.xyz, 0.0)).xyz;
 +}
 +
 +void node_tangent(vec3 N, vec3 orco, mat4 objmat, mat4 toworld, out vec3 T)
 +{
 +      N = (toworld * vec4(N, 0.0)).xyz;
 +      T = (objmat * vec4(orco, 0.0)).xyz;
 +      T = cross(N, normalize(cross(T, N)));
 +}
 +
  void node_geometry(
 -        vec3 I, vec3 N, mat4 toworld,
 +        vec3 I, vec3 N, vec3 orco, mat4 objmat, mat4 toworld,
          out vec3 position, out vec3 normal, out vec3 tangent,
          out vec3 true_normal, out vec3 incoming, out vec3 parametric,
          out float backfacing, out float pointiness)
  {
 +#ifdef EEVEE_ENGINE
 +      position = worldPosition;
 +#else
        position = (toworld * vec4(I, 1.0)).xyz;
 +#endif
        normal = (toworld * vec4(N, 0.0)).xyz;
 -      tangent = vec3(0.0);
 +      tangent_orco_z(orco, orco);
 +      node_tangent(N, orco, objmat, toworld, tangent);
        true_normal = normal;
  
        /* handle perspective/orthographic */
 -      vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
 +      vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
        incoming = -(toworld * vec4(I_view, 0.0)).xyz;
  
        parametric = vec3(0.0);
@@@ -3238,12 -2904,12 +3240,12 @@@ void node_tex_coord
          out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
          out vec3 camera, out vec3 window, out vec3 reflection)
  {
 -      generated = attr_orco * 0.5 + vec3(0.5);
 +      generated = attr_orco;
        normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz);
        uv = attr_uv;
        object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz;
        camera = vec3(I.xy, -I.z);
 -      vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
 +      vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
        window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
  
        vec3 shade_I;
@@@ -3258,18 -2924,13 +3260,18 @@@ void node_tex_coord_background
          out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
          out vec3 camera, out vec3 window, out vec3 reflection)
  {
 -      vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
 -      vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
 +      vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
 +      vec4 co_homogenous = (ProjectionMatrixInverse * v);
  
        vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
  
        co = normalize(co);
 -      vec3 coords = (gl_ModelViewMatrixInverse * co).xyz;
 +
 +#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
 +      vec3 coords = (ViewMatrixInverse * co).xyz;
 +#else
 +      vec3 coords = (ModelViewMatrixInverse * co).xyz;
 +#endif
  
        generated = coords;
        normal = -coords;
        object = coords;
  
        camera = vec3(co.xy, -co.z);
 -      window = (gl_ProjectionMatrix[3][3] == 0.0) ?
 +      window = (ProjectionMatrix[3][3] == 0.0) ?
                 vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
                 vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
  
        reflection = -coords;
  }
  
 +#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
 +#define node_tex_coord node_tex_coord_background
 +#endif
 +
  /* textures */
  
  float calc_gradient(vec3 p, int gradient_type)
@@@ -3357,6 -3014,7 +3359,6 @@@ void node_tex_checker(vec3 co, vec4 col
        fac = check ? 1.0 : 0.0;
  }
  
 -#ifdef BIT_OPERATIONS
  vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bias,
                          float brick_width, float row_height,
                          float offset_amount, int offset_frequency,
                return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
        }
  }
 -#endif
  
  void node_tex_brick(vec3 co,
                      vec4 color1, vec4 color2,
                      float squash_amount, float squash_frequency,
                      out vec4 color, out float fac)
  {
 -#ifdef BIT_OPERATIONS
        vec2 f2 = calc_brick_texture(co * scale,
                                     mortar_size, mortar_smooth, bias,
                                     brick_width, row_height,
        }
        color = mix(color1, mortar, f);
        fac = f;
 -#else
 -      color = vec4(1.0);
 -      fac = 1.0;
 -#endif
  }
  
  void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
@@@ -3429,15 -3093,7 +3431,15 @@@ void node_tex_environment_equirectangul
        float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
        float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
  
 -      color = texture2D(ima, vec2(u, v));
 +      /* Fix pole bleeding */
 +      float half_width = 0.5 / float(textureSize(ima, 0).x);
 +      v = clamp(v, half_width, 1.0 - half_width);
 +
 +      /* Fix u = 0 seam */
 +      /* This is caused by texture filtering, since uv don't have smooth derivatives
 +       * at u = 0 or 2PI, hardware filtering is using the smallest mipmap for certain
 +       * texels. So we force the highest mipmap and don't do anisotropic filtering. */
 +      color = textureLod(ima, vec2(u, v), 0.0);
  }
  
  void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
        float u = 0.5 * (nco.x + 1.0);
        float v = 0.5 * (nco.z + 1.0);
  
 -      color = texture2D(ima, vec2(u, v));
 +      color = texture(ima, vec2(u, v));
  }
  
  void node_tex_environment_empty(vec3 co, out vec4 color)
  
  void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
  {
 -      color = texture2D(ima, co.xy);
 +      color = texture(ima, co.xy);
        alpha = color.a;
  }
  
@@@ -3537,21 -3193,21 +3539,21 @@@ void node_tex_image_box(vec3 texco
                if(signed_N.x < 0.0) {
                        uv.x = 1.0 - uv.x;
                }
 -              color += weight.x * texture2D(ima, uv);
 +              color += weight.x * texture(ima, uv);
        }
        if (weight.y > 0.0) {
                vec2 uv = texco.xz;
                if(signed_N.y > 0.0) {
                        uv.x = 1.0 - uv.x;
                }
 -              color += weight.y * texture2D(ima, uv);
 +              color += weight.y * texture(ima, uv);
        }
        if (weight.z > 0.0) {
                vec2 uv = texco.yx;
                if(signed_N.z > 0.0) {
                        uv.x = 1.0 - uv.x;
                }
 -              color += weight.z * texture2D(ima, uv);
 +              color += weight.z * texture(ima, uv);
        }
  
        alpha = color.a;
@@@ -3624,6 -3280,7 +3626,6 @@@ void node_tex_magic(vec3 co, float scal
        fac = (color.x + color.y + color.z) / 3.0;
  }
  
 -#ifdef BIT_OPERATIONS
  float noise_fade(float t)
  {
        return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
@@@ -3698,9 -3355,10 +3700,9 @@@ float noise_turbulence(vec3 p, float oc
        float fscale = 1.0;
        float amp = 1.0;
        float sum = 0.0;
 -      int i, n;
        octaves = clamp(octaves, 0.0, 16.0);
 -      n = int(octaves);
 -      for (i = 0; i <= n; i++) {
 +      int n = int(octaves);
 +      for (int i = 0; i <= n; i++) {
                float t = noise(fscale * p);
                if (hard != 0) {
                        t = abs(2.0 * t - 1.0);
                fscale *= 2.0;
        }
        float rmd = octaves - floor(octaves);
 -      if  (rmd != 0.0) {
 +      if (rmd != 0.0) {
                float t = noise(fscale * p);
                if (hard != 0) {
                        t = abs(2.0 * t - 1.0);
                return sum;
        }
  }
 -#endif  // BIT_OPERATIONS
  
  void node_tex_noise(vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
  {
 -#ifdef BIT_OPERATIONS
        vec3 p = co * scale;
        int hard = 0;
        if (distortion != 0.0) {
                     noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
                     noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
                     1);
 -#else  // BIT_OPERATIONS
 -      color = vec4(1.0);
 -      fac = 1.0;
 -#endif  // BIT_OPERATIONS
  }
  
 -
 -#ifdef BIT_OPERATIONS
 -
  /* Musgrave fBm
   *
   * H: fractal increment parameter
@@@ -3760,8 -3427,9 +3762,8 @@@ float noise_musgrave_fBm(vec3 p, float 
        float value = 0.0;
        float pwr = 1.0;
        float pwHL = pow(lacunarity, -H);
 -      int i;
  
 -      for (i = 0; i < int(octaves); i++) {
 +      for (int i = 0; i < int(octaves); i++) {
                value += snoise(p) * pwr;
                pwr *= pwHL;
                p *= lacunarity;
@@@ -3787,8 -3455,9 +3789,8 @@@ float noise_musgrave_multi_fractal(vec
        float value = 1.0;
        float pwr = 1.0;
        float pwHL = pow(lacunarity, -H);
 -      int i;
  
 -      for (i = 0; i < int(octaves); i++) {
 +      for (int i = 0; i < int(octaves); i++) {
                value *= (pwr * snoise(p) + 1.0);
                pwr *= pwHL;
                p *= lacunarity;
@@@ -3814,12 -3483,13 +3816,12 @@@ float noise_musgrave_hetero_terrain(vec
        float value, increment, rmd;
        float pwHL = pow(lacunarity, -H);
        float pwr = pwHL;
 -      int i;
  
        /* first unscaled octave of function; later octaves are scaled */
        value = offset + snoise(p);
        p *= lacunarity;
  
 -      for (i = 1; i < int(octaves); i++) {
 +      for (int i = 1; i < int(octaves); i++) {
                increment = (snoise(p) + offset) * pwr * value;
                value += increment;
                pwr *= pwHL;
@@@ -3848,12 -3518,13 +3850,12 @@@ float noise_musgrave_hybrid_multi_fract
        float result, signal, weight, rmd;
        float pwHL = pow(lacunarity, -H);
        float pwr = pwHL;
 -      int i;
  
        result = snoise(p) + offset;
        weight = gain * result;
        p *= lacunarity;
  
 -      for (i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
 +      for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
                if (weight > 1.0)
                        weight = 1.0;
  
@@@ -3884,13 -3555,14 +3886,13 @@@ float noise_musgrave_ridged_multi_fract
        float result, signal, weight;
        float pwHL = pow(lacunarity, -H);
        float pwr = pwHL;
 -      int i;
  
        signal = offset - abs(snoise(p));
        signal *= signal;
        result = signal;
        weight = 1.0;
  
 -      for (i = 1; i < int(octaves); i++) {
 +      for (int i = 1; i < int(octaves); i++) {
                p *= lacunarity;
                weight = clamp(signal * gain, 0.0, 1.0);
                signal = offset - abs(snoise(p));
@@@ -3912,18 -3584,19 +3914,18 @@@ float svm_musgrave(int type
                     float gain,
                     vec3 p)
  {
 -      if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/)
 +      if (type == 0 /* NODE_MUSGRAVE_MULTIFRACTAL */)
                return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
 -      else if (type == 1 /*NODE_MUSGRAVE_FBM*/)
 +      else if (type == 1 /* NODE_MUSGRAVE_FBM */)
                return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
 -      else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/)
 +      else if (type == 2 /* NODE_MUSGRAVE_HYBRID_MULTIFRACTAL */)
                return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
 -      else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/)
 +      else if (type == 3 /* NODE_MUSGRAVE_RIDGED_MULTIFRACTAL */)
                return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
 -      else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/)
 +      else if (type == 4 /* NODE_MUSGRAVE_HETERO_TERRAIN */)
                return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
        return 0.0;
  }
 -#endif  // #ifdef BIT_OPERATIONS
  
  void node_tex_musgrave(vec3 co,
                         float scale,
                         out vec4 color,
                         out float fac)
  {
 -#ifdef BIT_OPERATIONS
        fac = svm_musgrave(int(type),
                           dimension,
                           lacunarity,
                           1.0,
                           gain,
                           co * scale);
 -#else
 -      fac = 1.0;
 -#endif
  
        color = vec4(fac, fac, fac, 1.0);
  }
@@@ -3955,6 -3632,7 +3957,6 @@@ void node_tex_sky(vec3 co, out vec4 col
  
  void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out float fac)
  {
 -#ifdef BIT_OPERATIONS
        vec3 p = co * scale;
        int xx, yy, zz, xi, yi, zi;
        float da[4];
                color = vec4(cellnoise_color(pa[0]), 1);
                fac = (color.x + color.y + color.z) * (1.0 / 3.0);
        }
 -#else  // BIT_OPERATIONS
 -      color = vec4(1.0);
 -      fac = 1.0;
 -#endif  // BIT_OPERATIONS
  }
  
 -#ifdef BIT_OPERATIONS
  float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
  {
        float n;
                return (n < 0.0) ? n + 1.0 : n;
        }
  }
 -#endif  // BIT_OPERATIONS
  
  void node_tex_wave(
          vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile,
          out vec4 color, out float fac)
  {
 -#ifdef BIT_OPERATIONS
        float f;
        f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
  
        color = vec4(f, f, f, 1.0);
        fac = f;
 -#else  // BIT_OPERATIONS
 -      color = vec4(1.0);
 -      fac = 1;
 -#endif  // BIT_OPERATIONS
  }
  
  /* light path */
@@@ -4071,21 -3760,13 +4073,21 @@@ void node_light_path
        out float transparent_depth,
        out float transmission_depth)
  {
 +#ifndef PROBE_CAPTURE
        is_camera_ray = 1.0;
 -      is_shadow_ray = 0.0;
 -      is_diffuse_ray = 0.0;
        is_glossy_ray = 0.0;
 -      is_singular_ray = 0.0;
 +      is_diffuse_ray = 0.0;
        is_reflection_ray = 0.0;
        is_transmission_ray = 0.0;
 +#else
 +      is_camera_ray = 0.0;
 +      is_glossy_ray = 1.0;
 +      is_diffuse_ray = 1.0;
 +      is_reflection_ray = 1.0;
 +      is_transmission_ray = 1.0;
 +#endif
 +      is_shadow_ray = 0.0;
 +      is_singular_ray = 0.0;
        ray_length = 1.0;
        ray_depth = 1.0;
        diffuse_depth = 1.0;
@@@ -4184,79 -3865,37 +4186,79 @@@ void node_vector_displacement_world(vec
  
  /* output */
  
 -void node_output_material(vec4 surface, vec4 volume, vec3 displacement, out vec4 result)
 +void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
  {
 +#ifdef VOLUMETRICS
 +      result = volume;
 +#else
        result = surface;
 +#endif
  }
  
 -void node_output_world(vec4 surface, vec4 volume, out vec4 result)
 +uniform float backgroundAlpha;
 +
 +void node_output_world(Closure surface, Closure volume, out Closure result)
  {
 -      result = surface;
 +#ifndef VOLUMETRICS
 +#ifdef EEVEE_ENGINE
 +      result.radiance = surface.radiance;
 +      result.opacity = backgroundAlpha;
 +#else
 +      result = Closure(surface.radiance, backgroundAlpha);
 +#endif
 +#else
 +      result = volume;
 +#endif /* VOLUMETRICS */
 +}
 +
 +#ifndef VOLUMETRICS
 +/* TODO : clean this ifdef mess */
 +/* EEVEE output */
 +#ifdef EEVEE_ENGINE
 +void world_normals_get(out vec3 N)
 +{
 +      N = gl_FrontFacing ? worldNormal : -worldNormal;
 +}
 +
 +void node_eevee_specular(
 +        vec4 diffuse, vec4 specular, float roughness, vec4 emissive, float transp, vec3 normal,
 +        float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
 +        float occlusion, float ssr_id, out Closure result)
 +{
 +      vec3 out_diff, out_spec, ssr_spec;
 +      eevee_closure_default(normal, diffuse.rgb, specular.rgb, int(ssr_id), roughness, occlusion,
 +                            out_diff, out_spec, ssr_spec);
 +
 +      vec3 vN = normalize(mat3(ViewMatrix) * normal);
 +      result = CLOSURE_DEFAULT;
 +      result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
 +      result.opacity = 1.0 - transp;
 +      result.ssr_data = vec4(ssr_spec, roughness);
 +      result.ssr_normal = normal_encode(vN, viewCameraVec);
 +      result.ssr_id = int(ssr_id);
  }
  
 +#endif /* EEVEE_ENGINE */
 +#endif /* VOLUMETRICS */
 +
  /* ********************** matcap style render ******************** */
  
  void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result)
  {
        vec3 normal;
 -      vec2 tex;
        
  #ifndef USE_OPENSUBDIV
        /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
         * between shader stages and we want the full range of the normal */
 -      normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0);
 -      if (normal.z < 0.0) {
 -              normal.z = 0.0;
 -      }
 +      normal = 2.0 * N.xyz - vec3(1.0);
 +      normal.z = max(normal.z, 0.0);
        normal = normalize(normal);
  #else
        normal = inpt.v.normal;
 -      mask = vec4(1.0, 1.0, 1.0, 1.0);
 +      mask = vec4(1.0);
  #endif
  
 -      tex.x = 0.5 + 0.49 * normal.x;
 -      tex.y = 0.5 + 0.49 * normal.y;
 -      result = texture2D(ima, tex) * mask;
 +      vec2 tex = 0.49 * normal.xy + vec2(0.5);
 +
 +      result = texture(ima, tex) * mask;
  }
index 24f0474a5b8dc3f5dde5f075e91ccca86407a484,3dbe5c81c570f126e461e1045dc5d33b8600b931..69fcbba8f884827b936de07510f5a13a625b5699
@@@ -29,6 -29,7 +29,7 @@@
  #include "RE_shader_ext.h"
  
  static bNodeSocketTemplate outputs[] = {
+       { SOCK_FLOAT,  0, "Index" },
        { SOCK_FLOAT,  0, "Random" },
        { SOCK_FLOAT,  0, "Age" },
        { SOCK_FLOAT,  0, "Lifetime" },
@@@ -45,13 -46,13 +46,13 @@@ static void node_shader_exec_particle_i
  {
        ShadeInput *shi = ((ShaderCallData *)data)->shi;
  
-       RE_instance_get_particle_info(shi->obi, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec, out[4]->vec, out[5]->vec, out[6]->vec);
+       RE_instance_get_particle_info(shi->obi, out[0]->vec, out[1]->vec, out[2]->vec, out[3]->vec, out[4]->vec, out[5]->vec, out[6]->vec, out[7]->vec);
  }
  
 -static int gpu_shader_particle_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
 +static int gpu_shader_particle_info(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
  {
  
 -      return GPU_stack_link(mat, "particle_info", in, out,
 +      return GPU_stack_link(mat, node, "particle_info", in, out,
                              GPU_builtin(GPU_PARTICLE_SCALAR_PROPS),
                              GPU_builtin(GPU_PARTICLE_LOCATION),
                              GPU_builtin(GPU_PARTICLE_VELOCITY),
index 0b392c122db9be220084b7a5fb243b3ebd40dc68,e1cb922f6a5d11d518596798ffdc712985746d6f..281f0082d7f5cdcb77fa0a4eff4e06605d3106c0
@@@ -179,6 -179,8 +179,6 @@@ typedef struct ShadeInput 
        unsigned int lay;
        int layflag, passflag, combinedflag;
        short object_pass_index;
 -      struct Group *light_override;
 -      struct Material *mat_override;
  
  #ifdef RE_RAYCOUNTER
        RayCounter raycounter;
@@@ -215,7 -217,7 +215,7 @@@ int multitex_nodes(struct Tex *tex, flo
                     const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex,
                     struct ImagePool *pool);
  float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]);
- void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]);
+ void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *random, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]);
  
  float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta);