diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-05-24 16:14:32 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-05-24 16:38:15 +0300 |
commit | 7a9ad029dd1d1afe42d54c9c181de887636db7c0 (patch) | |
tree | e9281cbe8bb01365a699ffd6f4bbd09a6a91015f /source/blender/blenkernel | |
parent | 707340edd703ff1fd7c8157eb3cc811913698c8d (diff) |
Remove TexFace, per-face images
TexFace complicates the now more popular shading pipeline by having
per-face images, see: T51382 for details.
To keep the ability to select a per-material edit-image
(used with UV-mapping workflow), the material now stores an image
which will be set when changing images in edit-mode.
This is used as a bake-target when not using Cycles too.
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r-- | source/blender/blenkernel/BKE_material.h | 7 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/customdata.c | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/library_query.c | 26 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/material.c | 508 |
4 files changed, 25 insertions, 518 deletions
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 8ae5c2b3c45..0a5d37631d1 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -86,6 +86,10 @@ short BKE_object_material_slot_find_index(struct Object *ob, struct Material *ma bool BKE_object_material_slot_add(struct Object *ob); bool BKE_object_material_slot_remove(struct Object *ob); +struct Image *BKE_object_material_edit_image_get(struct Object *ob, short mat_nr); +struct Image **BKE_object_material_edit_image_get_array(struct Object *ob); +bool BKE_object_material_edit_image_set(struct Object *ob, short mat_nr, struct Image *image); + void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma); void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob); @@ -114,9 +118,6 @@ void free_matcopybuf(void); void copy_matcopybuf(struct Material *ma); void paste_matcopybuf(struct Material *ma); -/* handle backward compatibility for tface/materials called from doversion */ -int do_version_tface(struct Main *main); - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 7c3f0ac630d..96b15a22554 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -419,7 +419,7 @@ static void layerSwap_tface(void *data, const int *corner_indices) static void layerDefault_tface(void *data, int count) { - static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, NULL, + static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}, 0, 0, TF_DYNAMIC | TF_CONVERTED, 0, 0}; MTFace *tf = (MTFace *)data; int i; diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 3c8d1c6d888..0c89a5bea42 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -643,31 +643,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call for (i = 0; i < mesh->totcol; i++) { CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER); } - - /* XXX Really not happy with this - probably texface should rather use some kind of - * 'texture slots' and just set indices in each poly/face item - would also save some memory. - * Maybe a nice TODO for blender2.8? */ - if (mesh->mtface || mesh->mtpoly) { - for (i = 0; i < mesh->pdata.totlayer; i++) { - if (mesh->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data; - - for (int j = 0; j < mesh->totpoly; j++, txface++) { - CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE); - } - } - } - - for (i = 0; i < mesh->fdata.totlayer; i++) { - if (mesh->fdata.layers[i].type == CD_MTFACE) { - MTFace *tface = (MTFace *)mesh->fdata.layers[i].data; - - for (int j = 0; j < mesh->totface; j++, tface++) { - CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE); - } - } - } - } break; } @@ -710,6 +685,7 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data); } CALLBACK_INVOKE(material->group, IDWALK_CB_USER); + CALLBACK_INVOKE(material->edit_image, IDWALK_CB_USER); break; } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index fb4aec0a380..61e3ede3e8a 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -229,6 +229,7 @@ Material *BKE_material_copy(Main *bmain, Material *ma) man = BKE_libblock_copy(bmain, &ma->id); id_lib_extern((ID *)man->group); + id_lib_extern((ID *)man->edit_image); for (a = 0; a < MAX_MTEX; a++) { if (ma->mtex[a]) { @@ -944,7 +945,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 */ } @@ -1767,501 +1768,30 @@ 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) +struct Image *BKE_object_material_edit_image_get(Object *ob, short mat_nr) { - 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; + Material *ma = give_current_material(ob, mat_nr + 1); + return ma ? ma->edit_image : NULL; } -/* boolean check to see if the mesh needs a material */ -static int check_tfaceneedmaterial(int flag) +struct Image **BKE_object_material_edit_image_get_array(Object *ob) { - /* 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) -{ - BKE_material_append_id(G.main, &me->id, NULL); - me->mat[me->totcol - 1] = ma; - - id_us_plus(&ma->id); - - return me->totcol - 1; -} - -static void set_facetexture_flags(Material *ma, Image *image) -{ - 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; - } -} - -/* returns material number */ -static short convert_tfacenomaterial(Main *main, Mesh *me, MTFace *tf, int flag) -{ - 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++; - } - } + 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; } - -#define MAT_BGE_DISPUTED -99999 - -int do_version_tface(Main *main) +bool BKE_object_material_edit_image_set(Object *ob, short mat_nr, Image *image) { - 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; - } - } - } - - } - - /* 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; - } - } + 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 nowarning; + return false; } - |