diff options
Diffstat (limited to 'source/blender/blenkernel/intern/material.c')
-rw-r--r-- | source/blender/blenkernel/intern/material.c | 1116 |
1 files changed, 78 insertions, 1038 deletions
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 74866fd1d94..0d41385a39c 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -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,9 @@ #include "BKE_editmesh.h" #include "BKE_font.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "GPU_material.h" /* used in UI and render */ @@ -87,16 +89,10 @@ void init_def_material(void) /** Free (or release) any data used by this material (does not free the material itself). */ void BKE_material_free(Material *ma) { - int a; - BKE_animdata_free((ID *)ma, false); - for (a = 0; a < MAX_MTEX; a++) { - MEM_SAFE_FREE(ma->mtex[a]); - } - - MEM_SAFE_FREE(ma->ramp_col); - MEM_SAFE_FREE(ma->ramp_spec); + /* Free gpu material before the ntree */ + GPU_material_free(&ma->gpumaterial); /* is no lib link block, but material extension */ if (ma->nodetree) { @@ -107,8 +103,6 @@ void BKE_material_free(Material *ma) MEM_SAFE_FREE(ma->texpaintslot); - GPU_material_free(&ma->gpumaterial); - BKE_icon_id_delete((ID *)ma); BKE_previewimg_free(&ma->preview); } @@ -117,95 +111,19 @@ void BKE_material_init(Material *ma) { BLI_assert(MEMCMP_STRUCT_OFS_IS_ZERO(ma, id)); - ma->r = ma->g = ma->b = ma->ref = 0.8; + ma->r = ma->g = ma->b = 0.8; ma->specr = ma->specg = ma->specb = 1.0; - ma->mirr = ma->mirg = ma->mirb = 1.0; - ma->spectra = 1.0; - ma->amb = 1.0; - ma->alpha = 1.0; - ma->spec = ma->hasize = 0.5; - ma->har = 50; - ma->starc = ma->ringc = 4; - ma->linec = 12; - ma->flarec = 1; - ma->flaresize = ma->subsize = 1.0; - ma->flareboost = 1; - ma->seed2 = 6; - ma->friction = 0.5; - ma->refrac = 4.0; - ma->roughness = 0.5; - ma->param[0] = 0.5; - ma->param[1] = 0.1; - ma->param[2] = 0.5; - ma->param[3] = 0.1; - ma->rms = 0.1; - ma->darkness = 1.0; - - ma->strand_sta = ma->strand_end = 1.0f; - - ma->ang = 1.0; - ma->ray_depth = 2; - ma->ray_depth_tra = 2; - ma->fresnel_mir = 0.0; - ma->fresnel_tra = 0.0; - ma->fresnel_tra_i = 1.25; - ma->fresnel_mir_i = 1.25; - ma->tx_limit = 0.0; - ma->tx_falloff = 1.0; - ma->shad_alpha = 1.0f; - ma->vcol_alpha = 0; - - ma->gloss_mir = ma->gloss_tra = 1.0; - ma->samp_gloss_mir = ma->samp_gloss_tra = 18; - ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005; - ma->dist_mir = 0.0; - ma->fadeto_mir = MA_RAYMIR_FADETOSKY; - - ma->rampfac_col = 1.0; - ma->rampfac_spec = 1.0; + // ma->alpha = 1.0; /* DEPRECATED */ + ma->spec = 0.5; + + ma->roughness = 0.25f; + ma->pr_lamp = 3; /* two lamps, is bits */ ma->pr_type = MA_SPHERE; - ma->sss_radius[0] = 1.0f; - ma->sss_radius[1] = 1.0f; - ma->sss_radius[2] = 1.0f; - ma->sss_col[0] = 1.0f; - ma->sss_col[1] = 1.0f; - ma->sss_col[2] = 1.0f; - ma->sss_error = 0.05f; - ma->sss_scale = 0.1f; - ma->sss_ior = 1.3f; - ma->sss_colfac = 1.0f; - ma->sss_texfac = 0.0f; - ma->sss_front = 1.0f; - ma->sss_back = 1.0f; - - ma->vol.density = 1.0f; - ma->vol.emission = 0.0f; - ma->vol.scattering = 1.0f; - ma->vol.reflection = 1.0f; - ma->vol.transmission_col[0] = ma->vol.transmission_col[1] = ma->vol.transmission_col[2] = 1.0f; - ma->vol.reflection_col[0] = ma->vol.reflection_col[1] = ma->vol.reflection_col[2] = 1.0f; - ma->vol.emission_col[0] = ma->vol.emission_col[1] = ma->vol.emission_col[2] = 1.0f; - ma->vol.density_scale = 1.0f; - ma->vol.depth_cutoff = 0.01f; - ma->vol.stepsize_type = MA_VOL_STEP_RANDOMIZED; - ma->vol.stepsize = 0.2f; - ma->vol.shade_type = MA_VOL_SHADE_SHADED; - ma->vol.shadeflag |= MA_VOL_PRECACHESHADING; - ma->vol.precache_resolution = 50; - ma->vol.ms_spread = 0.2f; - ma->vol.ms_diff = 1.f; - ma->vol.ms_intensity = 1.f; - - ma->game.flag = GEMAT_BACKCULL; - ma->game.alpha_blend = 0; - ma->game.face_orientation = 0; - - ma->mode = MA_TRACEBLE | MA_SHADBUF | MA_SHADOW | MA_RAYBIAS | MA_TANGENT_STR | MA_ZTRANSP; - 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) @@ -229,20 +147,6 @@ Material *BKE_material_add(Main *bmain, const char *name) */ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_src, const int flag) { - for (int a = 0; a < MAX_MTEX; a++) { - if (ma_src->mtex[a]) { - ma_dst->mtex[a] = MEM_mallocN(sizeof(*ma_dst->mtex[a]), __func__); - *ma_dst->mtex[a] = *ma_src->mtex[a]; - } - } - - if (ma_src->ramp_col) { - ma_dst->ramp_col = MEM_dupallocN(ma_src->ramp_col); - } - if (ma_src->ramp_spec) { - ma_dst->ramp_spec = MEM_dupallocN(ma_src->ramp_spec); - } - if (ma_src->nodetree) { /* Note: nodetree is *not* in bmain, however this specific case is handled at lower level * (see BKE_libblock_copy_ex()). */ @@ -261,6 +165,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) @@ -281,29 +187,24 @@ Material *BKE_material_localize(Material *ma) * ... Once f*** nodes are fully converted to that too :( */ Material *man; - int a; - - man = BKE_libblock_copy_nolib(&ma->id, false); - - /* no increment for texture ID users, in previewrender.c it prevents decrement */ - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a]) { - man->mtex[a] = MEM_mallocN(sizeof(MTex), "copymaterial"); - memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex)); - } - } - if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); - if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); + BKE_id_copy_ex( + NULL, &ma->id, (ID **)&man, + (LIB_ID_CREATE_NO_MAIN | + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_COPY_NO_PREVIEW | + LIB_ID_COPY_NO_ANIMDATA), + false); man->texpaintslot = NULL; man->preview = NULL; - if (ma->nodetree) - man->nodetree = ntreeLocalize(ma->nodetree); - BLI_listbase_clear(&man->gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ + + man->id.tag |= LIB_TAG_LOCALIZED; + return man; } @@ -458,7 +359,8 @@ void BKE_material_resize_id(Main *bmain, ID *id, short totcol, bool do_id_user) } *totcolp = totcol; - DAG_relations_tag_update(bmain); + DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } void BKE_material_append_id(Main *bmain, ID *id, Material *ma) @@ -475,7 +377,9 @@ 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_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } } @@ -509,7 +413,8 @@ 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_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } } @@ -536,7 +441,8 @@ void BKE_material_clear_id(Main *bmain, ID *id, bool update_data) material_data_index_clear_id(id); } - DAG_relations_tag_update(bmain); + DEG_id_tag_update(id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } } @@ -631,7 +537,8 @@ 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_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } void test_object_materials(Main *bmain, Object *ob, ID *id) @@ -936,278 +843,8 @@ bool BKE_object_material_slot_add(Main *bmain, Object *ob) return true; } -static void do_init_render_material(Main *bmain, Material *ma, int r_mode, float *amb) -{ - MTex *mtex; - int a, needuv = 0, needtang = 0; - - if (ma->flarec == 0) ma->flarec = 1; - - /* add all texcoflags from mtex, texco and mapto were cleared in advance */ - for (a = 0; a < MAX_MTEX; a++) { - - /* separate tex switching */ - if (ma->septex & (1 << a)) continue; - - mtex = ma->mtex[a]; - if (mtex && mtex->tex && (mtex->tex->type | (mtex->tex->use_nodes && mtex->tex->nodetree) )) { - - ma->texco |= mtex->texco; - ma->mapto |= mtex->mapto; - - /* always get derivatives for these textures */ - if (ELEM(mtex->tex->type, TEX_IMAGE, TEX_ENVMAP)) ma->texco |= TEXCO_OSA; - else if (mtex->texflag & (MTEX_COMPAT_BUMP | MTEX_3TAP_BUMP | MTEX_5TAP_BUMP | MTEX_BICUBIC_BUMP)) ma->texco |= TEXCO_OSA; - - if (ma->texco & (TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM | TEXCO_STRAND | TEXCO_STRESS)) needuv = 1; - else if (ma->texco & (TEXCO_GLOB | TEXCO_UV | TEXCO_OBJECT | TEXCO_SPEED)) needuv = 1; - else if (ma->texco & (TEXCO_LAVECTOR | TEXCO_VIEW)) needuv = 1; - - if ((ma->mapto & MAP_NORM) && (mtex->normapspace == MTEX_NSPACE_TANGENT)) - needtang = 1; - } - } - - if (needtang) ma->mode |= MA_NORMAP_TANG; - else ma->mode &= ~MA_NORMAP_TANG; - - if (ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP | MA_FACETEXTURE)) { - needuv = 1; - if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */ - } - if (needuv) ma->texco |= NEED_UV; - - /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */ - if (r_mode & R_RAYTRACE) { - if ((ma->mode & (MA_RAYMIRROR | MA_SHADOW_TRA)) || ((ma->mode & MA_TRANSP) && (ma->mode & MA_RAYTRANSP))) { - ma->texco |= NEED_UV | TEXCO_ORCO | TEXCO_REFL | TEXCO_NORM; - if (r_mode & R_OSA) ma->texco |= TEXCO_OSA; - } - } - - if (amb) { - ma->ambr = ma->amb * amb[0]; - ma->ambg = ma->amb * amb[1]; - ma->ambb = ma->amb * amb[2]; - } - - /* local group override */ - if ((ma->shade_flag & MA_GROUP_LOCAL) && ma->id.lib && ma->group && ma->group->id.lib) { - Group *group; - - for (group = bmain->group.first; group; group = group->id.next) { - if (!ID_IS_LINKED(group) && STREQ(group->id.name, ma->group->id.name)) { - ma->group = group; - } - } - } -} - -static void init_render_nodetree(Main *bmain, bNodeTree *ntree, Material *basemat, int r_mode, float *amb) -{ - bNode *node; - - /* parses the geom+tex nodes */ - ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l); - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - if (GS(node->id->name) == ID_MA) { - Material *ma = (Material *)node->id; - if (ma != basemat) { - do_init_render_material(bmain, ma, r_mode, amb); - basemat->texco |= ma->texco; - } - - basemat->mode_l |= ma->mode & ~(MA_MODE_PIPELINE | MA_SHLESS); - basemat->mode2_l |= ma->mode2 & ~MA_MODE2_PIPELINE; - /* basemat only considered shadeless if all node materials are too */ - if (!(ma->mode & MA_SHLESS)) - basemat->mode_l &= ~MA_SHLESS; - - if (ma->strand_surfnor > 0.0f) - basemat->mode_l |= MA_STR_SURFDIFF; - } - else if (node->type == NODE_GROUP) - init_render_nodetree(bmain, (bNodeTree *)node->id, basemat, r_mode, amb); - } - else if (node->typeinfo->type == SH_NODE_NORMAL_MAP) { - basemat->mode2_l |= MA_TANGENT_CONCRETE; - NodeShaderNormalMap *nm = node->storage; - bool taken_into_account = false; - for (int i = 0; i < basemat->nmap_tangent_names_count; i++) { - if (STREQ(basemat->nmap_tangent_names[i], nm->uv_map)) { - taken_into_account = true; - break; - } - } - if (!taken_into_account) { - BLI_assert(basemat->nmap_tangent_names_count < MAX_MTFACE + 1); - strcpy(basemat->nmap_tangent_names[basemat->nmap_tangent_names_count++], nm->uv_map); - } - } - } -} - -void init_render_material(Main *bmain, Material *mat, int r_mode, float *amb) -{ - - do_init_render_material(bmain, mat, r_mode, amb); - - if (mat->nodetree && mat->use_nodes) { - /* mode_l will take the pipeline options from the main material, and the or-ed - * result of non-pipeline options from the nodes. shadeless is an exception, - * mode_l will have it set when all node materials are shadeless. */ - mat->mode_l = (mat->mode & MA_MODE_PIPELINE) | MA_SHLESS; - mat->mode2_l = mat->mode2 & MA_MODE2_PIPELINE; - mat->nmap_tangent_names_count = 0; - init_render_nodetree(bmain, mat->nodetree, mat, r_mode, amb); - - if (!mat->nodetree->execdata) - mat->nodetree->execdata = ntreeShaderBeginExecTree(mat->nodetree); - } - else { - mat->mode_l = mat->mode; - mat->mode2_l = mat->mode2; - - if (mat->strand_surfnor > 0.0f) - mat->mode_l |= MA_STR_SURFDIFF; - } -} - -void init_render_materials(Main *bmain, int r_mode, float *amb, bool do_default_material) -{ - Material *ma; - - /* clear these flags before going over materials, to make sure they - * are cleared only once, otherwise node materials contained in other - * node materials can go wrong */ - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->id.us) { - ma->texco = 0; - ma->mapto = 0; - } - } - - /* two steps, first initialize, then or the flags for layers */ - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - /* is_used flag comes back in convertblender.c */ - ma->flag &= ~MA_IS_USED; - if (ma->id.us) - init_render_material(bmain, ma, r_mode, amb); - } - - if (do_default_material) { - init_render_material(bmain, &defmaterial, r_mode, amb); - } -} - -/* only needed for nodes now */ -void end_render_material(Material *mat) -{ - if (mat && mat->nodetree && mat->use_nodes) { - if (mat->nodetree->execdata) - ntreeShaderEndExecTree(mat->nodetree->execdata); - } -} - -void end_render_materials(Main *bmain) -{ - Material *ma; - for (ma = bmain->mat.first; ma; ma = ma->id.next) - if (ma->id.us) - end_render_material(ma); -} - -static bool material_in_nodetree(bNodeTree *ntree, Material *mat) -{ - bNode *node; - - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - if (GS(node->id->name) == ID_MA) { - if (node->id == (ID *)mat) { - return true; - } - } - else if (node->type == NODE_GROUP) { - if (material_in_nodetree((bNodeTree *)node->id, mat)) { - return true; - } - } - } - } - - return false; -} - -bool material_in_material(Material *parmat, Material *mat) -{ - if (parmat == mat) - return true; - else if (parmat->nodetree && parmat->use_nodes) - return material_in_nodetree(parmat->nodetree, mat); - else - return false; -} - - /* ****************** */ -/* Update drivers for materials in a nodetree */ -static void material_node_drivers_update(Scene *scene, bNodeTree *ntree, float ctime) -{ - bNode *node; - - /* nodetree itself */ - if (ntree->adt && ntree->adt->drivers.first) { - BKE_animsys_evaluate_animdata(scene, &ntree->id, ntree->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* nodes */ - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - if (GS(node->id->name) == ID_MA) { - material_drivers_update(scene, (Material *)node->id, ctime); - } - else if (node->type == NODE_GROUP) { - material_node_drivers_update(scene, (bNodeTree *)node->id, ctime); - } - } - } -} - -/* Calculate all drivers for materials - * FIXME: this is really a terrible method which may result in some things being calculated - * multiple times. However, without proper despgraph support for these things, we are forced - * into this sort of thing... - */ -void material_drivers_update(Scene *scene, Material *ma, float ctime) -{ - //if (G.f & G_DEBUG) - // printf("material_drivers_update(%s, %s)\n", scene->id.name, ma->id.name); - - /* Prevent infinite recursion by checking (and tagging the material) as having been visited already - * (see BKE_scene_update_tagged()). This assumes ma->id.tag & LIB_TAG_DOIT isn't set by anything else - * in the meantime... [#32017] - */ - if (ma->id.tag & LIB_TAG_DOIT) - return; - - ma->id.tag |= LIB_TAG_DOIT; - - /* material itself */ - if (ma->adt && ma->adt->drivers.first) { - BKE_animsys_evaluate_animdata(scene, &ma->id, ma->adt, ctime, ADT_RECALC_DRIVERS); - } - - /* nodes */ - if (ma->nodetree) { - material_node_drivers_update(scene, ma->nodetree, ctime); - } - - ma->id.tag &= ~LIB_TAG_DOIT; -} - bool BKE_object_material_slot_remove(Main *bmain, Object *ob) { Material *mao, ***matarar; @@ -1297,13 +934,6 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob) return true; } -static bool get_mtex_slot_valid_texpaint(struct MTex *mtex) -{ - return (mtex && (mtex->texco == TEXCO_UV) && - mtex->tex && (mtex->tex->type == TEX_IMAGE) && - mtex->tex->ima); -} - static bNode *nodetree_uv_node_recursive(bNode *node) { bNode *inode; @@ -1326,12 +956,8 @@ static bNode *nodetree_uv_node_recursive(bNode *node) void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) { - MTex **mtex; short count = 0; - short index = 0, i; - - 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); + short index = 0; if (!ma) return; @@ -1348,88 +974,50 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma) return; } - if (use_nodes || ma->use_nodes) { - bNode *node, *active_node; + bNode *node, *active_node; - if (!(ma->nodetree)) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } + if (!(ma->nodetree)) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; + } - for (node = ma->nodetree->nodes.first; node; node = node->next) { - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) - count++; - } + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) + count++; + } - if (count == 0) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } - ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); - - active_node = nodeGetActiveTexture(ma->nodetree); - - for (node = ma->nodetree->nodes.first; node; node = node->next) { - if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { - if (active_node == node) - ma->paint_active_slot = index; - ma->texpaintslot[index].ima = (Image *)node->id; - - /* for new renderer, we need to traverse the treeback in search of a UV node */ - if (use_nodes) { - bNode *uvnode = nodetree_uv_node_recursive(node); - - if (uvnode) { - NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage; - ma->texpaintslot[index].uvname = storage->uv_map; - /* set a value to index so UI knows that we have a valid pointer for the mesh */ - ma->texpaintslot[index].index = 0; - } - else { - /* just invalidate the index here so UV map does not get displayed on the UI */ - ma->texpaintslot[index].index = -1; - } - } - else { - ma->texpaintslot[index].index = -1; - } - index++; - } - } + if (count == 0) { + ma->paint_active_slot = 0; + ma->paint_clone_slot = 0; + return; } - else if (is_bi) { - for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { - if (get_mtex_slot_valid_texpaint(*mtex)) { - count++; - } - } + ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); - if (count == 0) { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } + active_node = nodeGetActiveTexture(ma->nodetree); - ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); + for (node = ma->nodetree->nodes.first; node; node = node->next) { + if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) { + if (active_node == node) + ma->paint_active_slot = index; + ma->texpaintslot[index].ima = (Image *)node->id; - for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) { - if (get_mtex_slot_valid_texpaint(*mtex)) { - ma->texpaintslot[index].ima = (*mtex)->tex->ima; - ma->texpaintslot[index].uvname = (*mtex)->uvname; - ma->texpaintslot[index].index = i; + /* for new renderer, we need to traverse the treeback in search of a UV node */ + bNode *uvnode = nodetree_uv_node_recursive(node); - index++; + if (uvnode) { + NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage; + ma->texpaintslot[index].uvname = storage->uv_map; + /* set a value to index so UI knows that we have a valid pointer for the mesh */ + ma->texpaintslot[index].valid = true; + } + else { + /* just invalidate the index here so UV map does not get displayed on the UI */ + ma->texpaintslot[index].valid = false; } + index++; } } - else { - ma->paint_active_slot = 0; - ma->paint_clone_slot = 0; - return; - } - ma->tot_slots = count; @@ -1685,21 +1273,6 @@ void clear_matcopybuf(void) void free_matcopybuf(void) { - int a; - - for (a = 0; a < MAX_MTEX; a++) { - if (matcopybuf.mtex[a]) { - MEM_freeN(matcopybuf.mtex[a]); - matcopybuf.mtex[a] = NULL; - } - } - - if (matcopybuf.ramp_col) MEM_freeN(matcopybuf.ramp_col); - if (matcopybuf.ramp_spec) MEM_freeN(matcopybuf.ramp_spec); - - matcopybuf.ramp_col = NULL; - matcopybuf.ramp_spec = NULL; - if (matcopybuf.nodetree) { ntreeFreeTree(matcopybuf.nodetree); MEM_freeN(matcopybuf.nodetree); @@ -1711,575 +1284,42 @@ void free_matcopybuf(void) void copy_matcopybuf(Main *bmain, Material *ma) { - int a; - MTex *mtex; - if (matcopied) free_matcopybuf(); memcpy(&matcopybuf, ma, sizeof(Material)); - if (matcopybuf.ramp_col) matcopybuf.ramp_col = MEM_dupallocN(matcopybuf.ramp_col); - if (matcopybuf.ramp_spec) matcopybuf.ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec); - for (a = 0; a < MAX_MTEX; a++) { - mtex = matcopybuf.mtex[a]; - if (mtex) { - matcopybuf.mtex[a] = MEM_dupallocN(mtex); - } - } matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false); matcopybuf.preview = NULL; BLI_listbase_clear(&matcopybuf.gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ matcopied = 1; } void paste_matcopybuf(Main *bmain, Material *ma) { - int a; - MTex *mtex; ID id; if (matcopied == 0) return; - /* free current mat */ - if (ma->ramp_col) MEM_freeN(ma->ramp_col); - if (ma->ramp_spec) MEM_freeN(ma->ramp_spec); - for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); - } + + /* Free gpu material before the ntree */ + GPU_material_free(&ma->gpumaterial); if (ma->nodetree) { ntreeFreeTree(ma->nodetree); MEM_freeN(ma->nodetree); } - GPU_material_free(&ma->gpumaterial); - id = (ma->id); memcpy(ma, &matcopybuf, sizeof(Material)); (ma->id) = id; - if (matcopybuf.ramp_col) ma->ramp_col = MEM_dupallocN(matcopybuf.ramp_col); - if (matcopybuf.ramp_spec) ma->ramp_spec = MEM_dupallocN(matcopybuf.ramp_spec); - - for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; - if (mtex) { - ma->mtex[a] = MEM_dupallocN(mtex); - if (mtex->tex) { - /* first check this is in main (we may have loaded another file) [#35500] */ - if (BLI_findindex(&bmain->tex, mtex->tex) != -1) { - id_us_plus((ID *)mtex->tex); - } - else { - ma->mtex[a]->tex = NULL; - } - } - } - } - ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, 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(Main *bmain, Mesh *me, Material *ma) +void BKE_material_eval(struct Depsgraph *depsgraph, Material *material) { - BKE_material_append_id(bmain, &me->id, NULL); - me->mat[me->totcol - 1] = ma; - - id_us_plus(&ma->id); - - return me->totcol - 1; + DEG_debug_print_eval(depsgraph, __func__, material->id.name, material); + GPU_material_free(&material->gpumaterial); } - -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 *bmain, 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(&bmain->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(bmain, 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(bmain, idname + 2); - - if (ma) { - printf("TexFace Convert: Material \"%s\" created.\n", idname + 2); - mat_nr = mesh_addmaterial(bmain, 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 *bmain, 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 = bmain->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(&bmain->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(bmain, me, mat_new); - } - /* create a new material */ - else { - mat_new = BKE_material_copy(bmain, 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(bmain, 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(bmain, &me->id, a, true); - } - else { - a++; - } - } - } -} - - -#define MAT_BGE_DISPUTED -99999 - -int do_version_tface(Main *main) -{ - 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(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(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(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; - } - } - } - - return nowarning; -} - |