Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / material.c
index f5be72c6b4dd6a17c7a11843ad6265172e9f0e4f..3a74252047188b004a3bcc12e2d310babaa48b96 100644 (file)
@@ -58,7 +58,6 @@
 #include "BKE_animsys.h"
 #include "BKE_displist.h"
 #include "BKE_global.h"
-#include "BKE_depsgraph.h"
 #include "BKE_icons.h"
 #include "BKE_image.h"
 #include "BKE_library.h"
@@ -73,6 +72,8 @@
 #include "BKE_editmesh.h"
 #include "BKE_font.h"
 
+#include "DEG_depsgraph_build.h"
+
 #include "GPU_material.h"
 
 /* used in UI and render */
@@ -206,6 +207,8 @@ void BKE_material_init(Material *ma)
        ma->mode2 = MA_CASTSHADOW;
        ma->shade_flag = MA_APPROX_OCCLUSION;
        ma->preview = NULL;
+
+       ma->alpha_threshold = 0.5f;
 }
 
 Material *BKE_material_add(Main *bmain, const char *name)
@@ -255,6 +258,8 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr
        }
 
        BLI_listbase_clear(&ma_dst->gpumaterial);
+
+       /* TODO Duplicate Engine Settings and set runtime to NULL */
 }
 
 Material *BKE_material_copy(Main *bmain, const Material *ma)
@@ -297,6 +302,8 @@ Material *localize_material(Material *ma)
                man->nodetree = ntreeLocalize(ma->nodetree);
        
        BLI_listbase_clear(&man->gpumaterial);
+
+       /* TODO Duplicate Engine Settings and set runtime to NULL */
        
        return man;
 }
@@ -452,7 +459,7 @@ void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user)
        }
        *totcolp = totcol;
 
-       DAG_relations_tag_update(bmain);
+       DEG_relations_tag_update(bmain);
 }
 
 void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
@@ -469,7 +476,7 @@ void BKE_material_append_id(Main *bmain, ID *id, Material *ma)
 
                id_us_plus((ID *)ma);
                test_all_objects_materials(bmain, id);
-               DAG_relations_tag_update(bmain);
+               DEG_relations_tag_update(bmain);
        }
 }
 
@@ -503,7 +510,7 @@ Material *BKE_material_pop_id(Main *bmain, ID *id, int index_i, bool update_data
                                material_data_index_remove_id(id, index);
                        }
 
-                       DAG_relations_tag_update(bmain);
+                       DEG_relations_tag_update(bmain);
                }
        }
        
@@ -530,7 +537,7 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data)
                        material_data_index_clear_id(id);
                }
 
-               DAG_relations_tag_update(bmain);
+               DEG_relations_tag_update(bmain);
        }
 }
 
@@ -625,7 +632,7 @@ void BKE_material_resize_object(Main *bmain, Object *ob, const short totcol, boo
        if (ob->totcol && ob->actcol == 0) ob->actcol = 1;
        if (ob->actcol > ob->totcol) ob->actcol = ob->totcol;
 
-       DAG_relations_tag_update(bmain);
+       DEG_relations_tag_update(bmain);
 }
 
 void test_object_materials(Object *ob, ID *id)
@@ -965,7 +972,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
        if (needtang) ma->mode |= MA_NORMAP_TANG;
        else ma->mode &= ~MA_NORMAP_TANG;
        
-       if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) {
+       if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) {
                needuv = 1;
                if (r_mode & R_OSA) ma->texco |= TEXCO_OSA;     /* for texfaces */
        }
@@ -1326,6 +1333,14 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
 
        bool use_nodes = BKE_scene_use_new_shading_nodes(scene);
        bool is_bi = BKE_scene_uses_blender_internal(scene) || BKE_scene_uses_blender_game(scene);
+
+       /* XXX, for 2.8 testing & development its useful to have non Cycles/BI engines use material nodes
+        * In the future we may have some way to check this which each engine can define.
+        * For now use material slots for Clay/Eevee.
+        * - Campbell */
+       if (!(use_nodes || is_bi)) {
+               is_bi = true;
+       }
        
        if (!ma)
                return;
@@ -1724,6 +1739,7 @@ void copy_matcopybuf(Material *ma)
        matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, G.main, false);
        matcopybuf.preview = NULL;
        BLI_listbase_clear(&matcopybuf.gpumaterial);
+       /* TODO Duplicate Engine Settings and set runtime to NULL */
        matcopied = 1;
 }
 
@@ -1779,501 +1795,40 @@ void paste_matcopybuf(Material *ma)
        ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, G.main, false);
 }
 
-
-/*********************** texface to material convert functions **********************/
-/* encode all the TF information into a single int */
-static int encode_tfaceflag(MTFace *tf, int convertall)
-{
-       /* calculate the flag */
-       int flag = tf->mode;
-
-       /* options that change the material offline render */
-       if (!convertall) {
-               flag &= ~TF_OBCOL;
-       }
-
-       /* clean flags that are not being converted */
-       flag &= ~TF_TEX;
-       flag &= ~TF_SHAREDVERT;
-       flag &= ~TF_SHAREDCOL;
-       flag &= ~TF_CONVERTED;
-
-       /* light tface flag is ignored in GLSL mode */
-       flag &= ~TF_LIGHT;
-       
-       /* 15 is how big the flag can be - hardcoded here and in decode_tfaceflag() */
-       flag |= tf->transp << 15;
-       
-       /* increase 1 so flag 0 is different than no flag yet */
-       return flag + 1;
-}
-
-/* set the material options based in the tface flag */
-static void decode_tfaceflag(Material *ma, int flag, int convertall)
-{
-       int alphablend;
-       GameSettings *game = &ma->game;
-
-       /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
-       flag -= 1;
-
-       alphablend = flag >> 15;  /* encoded in the encode_tfaceflag function */
-       (*game).flag = 0;
-       
-       /* General Material Options */
-       if ((flag & TF_DYNAMIC) == 0) (*game).flag    |= GEMAT_NOPHYSICS;
-       
-       /* Material Offline Rendering Properties */
-       if (convertall) {
-               if (flag & TF_OBCOL) ma->shade_flag |= MA_OBCOLOR;
-       }
-       
-       /* Special Face Properties */
-       if ((flag & TF_TWOSIDE) == 0) (*game).flag |= GEMAT_BACKCULL;
-       if (flag & TF_INVISIBLE) (*game).flag |= GEMAT_INVISIBLE;
-       if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT;
-       
-       /* Face Orientation */
-       if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO;
-       else if (flag & TF_BILLBOARD2) (*game).face_orientation |= GEMAT_BILLBOARD;
-       else if (flag & TF_SHADOW) (*game).face_orientation |= GEMAT_SHADOW;
-       
-       /* Alpha Blend */
-       if (flag & TF_ALPHASORT && ELEM(alphablend, TF_ALPHA, TF_ADD)) (*game).alpha_blend = GEMAT_ALPHA_SORT;
-       else if (alphablend & TF_ALPHA) (*game).alpha_blend = GEMAT_ALPHA;
-       else if (alphablend & TF_ADD) (*game).alpha_blend = GEMAT_ADD;
-       else if (alphablend & TF_CLIP) (*game).alpha_blend = GEMAT_CLIP;
-}
-
-/* boolean check to see if the mesh needs a material */
-static int check_tfaceneedmaterial(int flag)
-{
-       /* check if the flags we have are not deprecated != than default material options
-        * also if only flags are visible and collision see if all objects using this mesh have this option in physics */
-
-       /* flag is shifted in 1 to make 0 != no flag yet (see encode_tfaceflag) */
-       flag -= 1;
-
-       /* deprecated flags */
-       flag &= ~TF_OBCOL;
-       flag &= ~TF_SHAREDVERT;
-       flag &= ~TF_SHAREDCOL;
-
-       /* light tface flag is ignored in GLSL mode */
-       flag &= ~TF_LIGHT;
-       
-       /* automatic detected if tex image has alpha */
-       flag &= ~(TF_ALPHA << 15);
-       /* automatic detected if using texture */
-       flag &= ~TF_TEX;
-
-       /* settings for the default NoMaterial */
-       if (flag == TF_DYNAMIC)
-               return 0;
-
-       else
-               return 1;
-}
-
-/* return number of digits of an integer */
-/* XXX to be optmized or replaced by an equivalent blender internal function */
-static int integer_getdigits(int number)
-{
-       int i = 0;
-       if (number == 0) return 1;
-
-       while (number != 0) {
-               number = (int)(number / 10);
-               i++;
-       }
-       return i;
-}
-
-static void calculate_tface_materialname(char *matname, char *newname, int flag)
-{
-       /* if flag has only light and collision and material matches those values
-        * you can do strcpy(name, mat_name);
-        * otherwise do: */
-       int digits = integer_getdigits(flag);
-       /* clamp the old name, remove the MA prefix and add the .TF.flag suffix
-        * e.g. matname = "MALoooooooooooooongName"; newname = "Loooooooooooooon.TF.2" */
-       BLI_snprintf(newname, MAX_ID_NAME, "%.*s.TF.%0*d", MAX_ID_NAME - (digits + 5), matname, digits, flag);
-}
-
-/* returns -1 if no match */
-static short mesh_getmaterialnumber(Mesh *me, Material *ma)
-{
-       short a;
-
-       for (a = 0; a < me->totcol; a++) {
-               if (me->mat[a] == ma) {
-                       return a;
-               }
-       }
-
-       return -1;
-}
-
-/* append material */
-static short mesh_addmaterial(Mesh *me, Material *ma)
+struct Image *BKE_object_material_edit_image_get(Object *ob, short mat_nr)
 {
-       BKE_material_append_id(G.main, &me->id, NULL);
-       me->mat[me->totcol - 1] = ma;
-
-       id_us_plus(&ma->id);
-
-       return me->totcol - 1;
+       Material *ma = give_current_material(ob, mat_nr + 1);
+       return ma ? ma->edit_image : NULL;
 }
 
-static void set_facetexture_flags(Material *ma, Image *image)
+struct Image **BKE_object_material_edit_image_get_array(Object *ob)
 {
-       if (image) {
-               ma->mode |= MA_FACETEXTURE;
-               /* we could check if the texture has alpha, but then more meshes sharing the same
-                * material may need it. Let's make it simple. */
-               if (BKE_image_has_alpha(image))
-                       ma->mode |= MA_FACETEXTURE_ALPHA;
+       Image **image_array = MEM_mallocN(sizeof(Material *) * ob->totcol, __func__);
+       for (int i = 0; i < ob->totcol; i++) {
+               image_array[i] = BKE_object_material_edit_image_get(ob, i);
        }
+       return image_array;
 }
 
-/* returns material number */
-static short convert_tfacenomaterial(Main *main, Mesh *me, MTFace *tf, int flag)
+bool BKE_object_material_edit_image_set(Object *ob, short mat_nr, Image *image)
 {
-       Material *ma;
-       char idname[MAX_ID_NAME];
-       short mat_nr = -1;
-       
-       /* new material, the name uses the flag*/
-       BLI_snprintf(idname, sizeof(idname), "MAMaterial.TF.%0*d", integer_getdigits(flag), flag);
-
-       if ((ma = BLI_findstring(&main->mat, idname + 2, offsetof(ID, name) + 2))) {
-               mat_nr = mesh_getmaterialnumber(me, ma);
-               /* assign the material to the mesh */
-               if (mat_nr == -1) mat_nr = mesh_addmaterial(me, ma);
-
-               /* if needed set "Face Textures [Alpha]" Material options */
-               set_facetexture_flags(ma, tf->tpage);
-       }
-       /* create a new material */
-       else {
-               ma = BKE_material_add(main, idname + 2);
-
-               if (ma) {
-                       printf("TexFace Convert: Material \"%s\" created.\n", idname + 2);
-                       mat_nr = mesh_addmaterial(me, ma);
-                       
-                       /* if needed set "Face Textures [Alpha]" Material options */
-                       set_facetexture_flags(ma, tf->tpage);
-
-                       decode_tfaceflag(ma, flag, 1);
-                       /* the final decoding will happen after, outside the main loop
-                        * for now store the flag into the material and change light/tex/collision
-                        * store the flag as a negative number */
-                       ma->game.flag = -flag;
-                       id_us_min((ID *)ma);
-               }
-               else {
-                       printf("Error: Unable to create Material \"%s\" for Mesh \"%s\".", idname + 2, me->id.name + 2);
-               }
-       }
-
-       /* set as converted, no need to go bad to this face */
-       tf->mode |= TF_CONVERTED;
-       return mat_nr;
-}
-
-/* Function to fully convert materials */
-static void convert_tfacematerial(Main *main, Material *ma)
-{
-       Mesh *me;
-       Material *mat_new;
-       MFace *mf;
-       MTFace *tf;
-       int flag, index;
-       int a;
-       short mat_nr;
-       CustomDataLayer *cdl;
-       char idname[MAX_ID_NAME];
-
-       for (me = main->mesh.first; me; me = me->id.next) {
-               /* check if this mesh uses this material */
-               for (a = 0; a < me->totcol; a++)
-                       if (me->mat[a] == ma) break;
-                       
-               /* no material found */
-               if (a == me->totcol) continue;
-
-               /* get the active tface layer */
-               index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
-               cdl = (index == -1) ? NULL : &me->fdata.layers[index];
-               if (!cdl) continue;
-
-               /* loop over all the faces and stop at the ones that use the material*/
-               for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
-                       if (me->mat[mf->mat_nr] != ma) continue;
-
-                       /* texface data for this face */
-                       tf = ((MTFace *)cdl->data) + a;
-                       flag = encode_tfaceflag(tf, 1);
-
-                       /* the name of the new material */
-                       calculate_tface_materialname(ma->id.name, (char *)&idname, flag);
-
-                       if ((mat_new = BLI_findstring(&main->mat, idname + 2, offsetof(ID, name) + 2))) {
-                               /* material already existent, see if the mesh has it */
-                               mat_nr = mesh_getmaterialnumber(me, mat_new);
-                               /* material is not in the mesh, add it */
-                               if (mat_nr == -1) mat_nr = mesh_addmaterial(me, mat_new);
-                       }
-                       /* create a new material */
-                       else {
-                               mat_new = BKE_material_copy(main, ma);
-                               if (mat_new) {
-                                       /* rename the material*/
-                                       BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name));
-                                       id_us_min((ID *)mat_new);
-
-                                       mat_nr = mesh_addmaterial(me, mat_new);
-                                       decode_tfaceflag(mat_new, flag, 1);
-                               }
-                               else {
-                                       printf("Error: Unable to create Material \"%s\" for Mesh \"%s.", idname + 2, me->id.name + 2);
-                                       mat_nr = mf->mat_nr;
-                                       continue;
-                               }
-                       }
-                       
-                       /* if the material has a texture but no texture channel
-                        * set "Face Textures [Alpha]" Material options 
-                        * actually we need to run it always, because of old behavior
-                        * of using face texture if any texture channel was present (multitex) */
-                       //if ((!mat_new->mtex[0]) && (!mat_new->mtex[0]->tex))
-                       set_facetexture_flags(mat_new, tf->tpage);
-
-                       /* set the material number to the face*/
-                       mf->mat_nr = mat_nr;
-               }
-               /* remove material from mesh */
-               for (a = 0; a < me->totcol; ) {
-                       if (me->mat[a] == ma) {
-                               BKE_material_pop_id(main, &me->id, a, true);
-                       }
-                       else {
-                               a++;
-                       }
-               }
+       Material *ma = give_current_material(ob, mat_nr + 1);
+       if (ma) {
+               /* both may be NULL */
+               id_us_min((ID *)ma->edit_image);
+               ma->edit_image = image;
+               id_us_plus((ID *)ma->edit_image);
+               return true;
        }
+       return false;
 }
 
-
-#define MAT_BGE_DISPUTED -99999
-
-int do_version_tface(Main *main)
+void BKE_material_eval(const struct EvaluationContext *UNUSED(eval_ctx), Material *material)
 {
-       Mesh *me;
-       Material *ma;
-       MFace *mf;
-       MTFace *tf;
-       CustomDataLayer *cdl;
-       int a;
-       int flag;
-       int index;
-       
-       /* Operator in help menu has been removed for 2.7x */
-       int fileload = 1;
-
-       /* sometimes mesh has no materials but will need a new one. In those
-        * cases we need to ignore the mf->mat_nr and only look at the face
-        * mode because it can be zero as uninitialized or the 1st created material
-        */
-       int nomaterialslots;
-
-       /* alert to user to check the console */
-       int nowarning = 1;
-
-       /* mark all the materials to conversion with a flag
-        * if there is tface create a complete flag for that storing in flag
-        * if there is tface and flag > 0: creates a new flag based on this face
-        * if flags are different set flag to -1  
-        */
-       
-       /* 1st part: marking mesh materials to update */
-       for (me = main->mesh.first; me; me = me->id.next) {
-               if (ID_IS_LINKED_DATABLOCK(me)) continue;
-
-               /* get the active tface layer */
-               index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
-               cdl = (index == -1) ? NULL : &me->fdata.layers[index];
-               if (!cdl) continue;
-
-               nomaterialslots = (me->totcol == 0 ? 1 : 0);
-               
-               /* loop over all the faces*/
-               for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
-                       /* texface data for this face */
-                       tf = ((MTFace *)cdl->data) + a;
-
-                       /* conversion should happen only once */
-                       if (fileload)
-                               tf->mode &= ~TF_CONVERTED;
-                       else {
-                               if ((tf->mode & TF_CONVERTED)) continue;
-                               else tf->mode |= TF_CONVERTED;
-                       }
-                       
-                       /* no material slots */
-                       if (nomaterialslots) {
-                               flag = encode_tfaceflag(tf, 1);
-                               
-                               /* create/find a new material and assign to the face */
-                               if (check_tfaceneedmaterial(flag)) {
-                                       mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
-                               }
-                               /* else mark them as no-material to be reverted to 0 later */
-                               else {
-                                       mf->mat_nr = -1;
-                               }
-                       }
-                       else if (mf->mat_nr < me->totcol) {
-                               ma = me->mat[mf->mat_nr];
-                               
-                               /* no material create one if necessary */
-                               if (!ma) {
-                                       /* find a new material and assign to the face */
-                                       flag = encode_tfaceflag(tf, 1);
-
-                                       /* create/find a new material and assign to the face */
-                                       if (check_tfaceneedmaterial(flag))
-                                               mf->mat_nr = convert_tfacenomaterial(main, me, tf, flag);
-
-                                       continue;
-                               }
-
-                               /* we can't read from this if it comes from a library,
-                                * at doversion time: direct_link might not have happened on it,
-                                * so ma->mtex is not pointing to valid memory yet.
-                                * later we could, but it's better not */
-                               else if (ID_IS_LINKED_DATABLOCK(ma))
-                                       continue;
-                               
-                               /* material already marked as disputed */
-                               else if (ma->game.flag == MAT_BGE_DISPUTED)
-                                       continue;
-
-                               /* found a material */
-                               else {
-                                       flag = encode_tfaceflag(tf, ((fileload) ? 0 : 1));
-
-                                       /* first time changing this material */
-                                       if (ma->game.flag == 0)
-                                               ma->game.flag = -flag;
-                       
-                                       /* mark material as disputed */
-                                       else if (ma->game.flag != -flag) {
-                                               ma->game.flag = MAT_BGE_DISPUTED;
-                                               continue;
-                                       }
-                       
-                                       /* material ok so far */
-                                       else {
-                                               ma->game.flag = -flag;
-                                               
-                                               /* some people uses multitexture with TexFace by creating a texture
-                                                * channel which not necessarily the tf->tpage image. But the game engine
-                                                * was enabling it. Now it's required to set "Face Texture [Alpha] in the
-                                                * material settings. */
-                                               if (!fileload)
-                                                       set_facetexture_flags(ma, tf->tpage);
-                                       }
-                               }
-                       }
-                       else {
-                               continue;
-                       }
-               }
-
-               /* if we didn't have material slot and now we do, we need to
-                * make sure the materials are correct */
-               if (nomaterialslots) {
-                       if (me->totcol > 0) {
-                               for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
-                                       if (mf->mat_nr == -1) {
-                                               /* texface data for this face */
-                                               tf = ((MTFace *)cdl->data) + a;
-                                               mf->mat_nr = convert_tfacenomaterial(main, me, tf, encode_tfaceflag(tf, 1));
-                                       }
-                               }
-                       }
-                       else {
-                               for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
-                                       mf->mat_nr = 0;
-                               }
-                       }
-               }
-
+       if (G.debug & G_DEBUG_DEPSGRAPH) {
+               printf("%s on %s (%p)\n", __func__, material->id.name, material);
        }
-       
-       /* 2nd part - conversion */
-       /* skip library files */
-
-       /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */
-       for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) {
-               if (ID_IS_LINKED_DATABLOCK(ma)) continue;
-
-               /* disputed material */
-               if (ma->game.flag == MAT_BGE_DISPUTED) {
-                       ma->game.flag = 0;
-                       if (fileload) {
-                               printf("Warning: material \"%s\" skipped.\n", ma->id.name + 2);
-                               nowarning = 0;
-                       }
-                       else {
-                               convert_tfacematerial(main, ma);
-                       }
-                       continue;
-               }
-       
-               /* no conflicts in this material - 90% of cases
-                * convert from tface system to material */
-               else if (ma->game.flag < 0) {
-                       decode_tfaceflag(ma, -(ma->game.flag), 1);
-
-                       /* material is good make sure all faces using
-                        * this material are set to converted */
-                       if (fileload) {
-                               for (me = main->mesh.first; me; me = me->id.next) {
-                                       /* check if this mesh uses this material */
-                                       for (a = 0; a < me->totcol; a++)
-                                               if (me->mat[a] == ma) break;
-                                               
-                                       /* no material found */
-                                       if (a == me->totcol) continue;
-                       
-                                       /* get the active tface layer */
-                                       index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
-                                       cdl = (index == -1) ? NULL : &me->fdata.layers[index];
-                                       if (!cdl) continue;
-                       
-                                       /* loop over all the faces and stop at the ones that use the material*/
-                                       for (a = 0, mf = me->mface; a < me->totface; a++, mf++) {
-                                               if (me->mat[mf->mat_nr] == ma) {
-                                                       /* texface data for this face */
-                                                       tf = ((MTFace *)cdl->data) + a;
-                                                       tf->mode |= TF_CONVERTED;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               /* material is not used by faces with texface
-                * set the default flag - do it only once */
-               else {
-                       if (fileload) {
-                               ma->game.flag = GEMAT_BACKCULL;
-                       }
-               }
+       if ((BLI_listbase_is_empty(&material->gpumaterial) == false)) {
+               GPU_material_uniform_buffer_tag_dirty(&material->gpumaterial);
        }
-
-       return nowarning;
 }
-