Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/material.cc
- This file was moved from source/blender/blenkernel/intern/material.c.
| Show First 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| Material *material_dst = (Material *)id_dst; | Material *material_dst = (Material *)id_dst; | ||||
| const Material *material_src = (const Material *)id_src; | const Material *material_src = (const Material *)id_src; | ||||
| const bool is_localized = (flag & LIB_ID_CREATE_LOCAL) != 0; | const bool is_localized = (flag & LIB_ID_CREATE_LOCAL) != 0; | ||||
| /* We always need allocation of our private ID data. */ | /* We always need allocation of our private ID data. */ | ||||
| const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE; | const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE; | ||||
| if (material_src->nodetree != NULL) { | if (material_src->nodetree != nullptr) { | ||||
| if (is_localized) { | if (is_localized) { | ||||
| material_dst->nodetree = ntreeLocalize(material_src->nodetree); | material_dst->nodetree = ntreeLocalize(material_src->nodetree); | ||||
| } | } | ||||
| else { | else { | ||||
| BKE_id_copy_ex(bmain, | BKE_id_copy_ex(bmain, | ||||
| (ID *)material_src->nodetree, | (ID *)material_src->nodetree, | ||||
| (ID **)&material_dst->nodetree, | (ID **)&material_dst->nodetree, | ||||
| flag_private_id_data); | flag_private_id_data); | ||||
| } | } | ||||
| material_dst->nodetree->owner_id = &material_dst->id; | material_dst->nodetree->owner_id = &material_dst->id; | ||||
| } | } | ||||
| if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { | if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { | ||||
| BKE_previewimg_id_copy(&material_dst->id, &material_src->id); | BKE_previewimg_id_copy(&material_dst->id, &material_src->id); | ||||
| } | } | ||||
| else { | else { | ||||
| material_dst->preview = NULL; | material_dst->preview = nullptr; | ||||
| } | } | ||||
| if (material_src->texpaintslot != NULL) { | if (material_src->texpaintslot != nullptr) { | ||||
| /* TODO: Think we can also skip copying this data in the more generic `NO_MAIN` case? */ | /* TODO: Think we can also skip copying this data in the more generic `NO_MAIN` case? */ | ||||
| material_dst->texpaintslot = is_localized ? NULL : MEM_dupallocN(material_src->texpaintslot); | material_dst->texpaintslot = is_localized ? nullptr : | ||||
| static_cast<TexPaintSlot *>( | |||||
| MEM_dupallocN(material_src->texpaintslot)); | |||||
| } | } | ||||
| if (material_src->gp_style != NULL) { | if (material_src->gp_style != nullptr) { | ||||
| material_dst->gp_style = MEM_dupallocN(material_src->gp_style); | material_dst->gp_style = static_cast<MaterialGPencilStyle *>( | ||||
| MEM_dupallocN(material_src->gp_style)); | |||||
| } | } | ||||
| BLI_listbase_clear(&material_dst->gpumaterial); | BLI_listbase_clear(&material_dst->gpumaterial); | ||||
| /* TODO: Duplicate Engine Settings and set runtime to NULL. */ | /* TODO: Duplicate Engine Settings and set runtime to nullptr. */ | ||||
| } | } | ||||
| static void material_free_data(ID *id) | static void material_free_data(ID *id) | ||||
| { | { | ||||
| Material *material = (Material *)id; | Material *material = (Material *)id; | ||||
| /* Free gpu material before the ntree */ | /* Free gpu material before the ntree */ | ||||
| GPU_material_free(&material->gpumaterial); | GPU_material_free(&material->gpumaterial); | ||||
| /* is no lib link block, but material extension */ | /* is no lib link block, but material extension */ | ||||
| if (material->nodetree) { | if (material->nodetree) { | ||||
| ntreeFreeEmbeddedTree(material->nodetree); | ntreeFreeEmbeddedTree(material->nodetree); | ||||
| MEM_freeN(material->nodetree); | MEM_freeN(material->nodetree); | ||||
| material->nodetree = NULL; | material->nodetree = nullptr; | ||||
| } | } | ||||
| MEM_SAFE_FREE(material->texpaintslot); | MEM_SAFE_FREE(material->texpaintslot); | ||||
| MEM_SAFE_FREE(material->gp_style); | MEM_SAFE_FREE(material->gp_style); | ||||
| BKE_icon_id_delete((ID *)material); | BKE_icon_id_delete((ID *)material); | ||||
| BKE_previewimg_free(&material->preview); | BKE_previewimg_free(&material->preview); | ||||
| } | } | ||||
| static void material_foreach_id(ID *id, LibraryForeachIDData *data) | static void material_foreach_id(ID *id, LibraryForeachIDData *data) | ||||
| { | { | ||||
| Material *material = (Material *)id; | Material *material = (Material *)id; | ||||
| /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */ | /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */ | ||||
| BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( | BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( | ||||
| data, BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)); | data, BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)); | ||||
| if (material->texpaintslot != NULL) { | if (material->texpaintslot != nullptr) { | ||||
| BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->texpaintslot->ima, IDWALK_CB_NOP); | BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->texpaintslot->ima, IDWALK_CB_NOP); | ||||
| } | } | ||||
| if (material->gp_style != NULL) { | if (material->gp_style != nullptr) { | ||||
| BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->sima, IDWALK_CB_USER); | BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->sima, IDWALK_CB_USER); | ||||
| BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->ima, IDWALK_CB_USER); | BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->gp_style->ima, IDWALK_CB_USER); | ||||
| } | } | ||||
| } | } | ||||
| static void material_blend_write(BlendWriter *writer, ID *id, const void *id_address) | static void material_blend_write(BlendWriter *writer, ID *id, const void *id_address) | ||||
| { | { | ||||
| Material *ma = (Material *)id; | Material *ma = (Material *)id; | ||||
| /* Clean up, important in undo case to reduce false detection of changed datablocks. */ | /* Clean up, important in undo case to reduce false detection of changed datablocks. */ | ||||
| ma->texpaintslot = NULL; | ma->texpaintslot = nullptr; | ||||
| BLI_listbase_clear(&ma->gpumaterial); | BLI_listbase_clear(&ma->gpumaterial); | ||||
| /* write LibData */ | /* write LibData */ | ||||
| BLO_write_id_struct(writer, Material, id_address, &ma->id); | BLO_write_id_struct(writer, Material, id_address, &ma->id); | ||||
| BKE_id_blend_write(writer, &ma->id); | BKE_id_blend_write(writer, &ma->id); | ||||
| if (ma->adt) { | if (ma->adt) { | ||||
| BKE_animdata_blend_write(writer, ma->adt); | BKE_animdata_blend_write(writer, ma->adt); | ||||
| Show All 14 Lines | |||||
| } | } | ||||
| static void material_blend_read_data(BlendDataReader *reader, ID *id) | static void material_blend_read_data(BlendDataReader *reader, ID *id) | ||||
| { | { | ||||
| Material *ma = (Material *)id; | Material *ma = (Material *)id; | ||||
| BLO_read_data_address(reader, &ma->adt); | BLO_read_data_address(reader, &ma->adt); | ||||
| BKE_animdata_blend_read_data(reader, ma->adt); | BKE_animdata_blend_read_data(reader, ma->adt); | ||||
| ma->texpaintslot = NULL; | ma->texpaintslot = nullptr; | ||||
| BLO_read_data_address(reader, &ma->preview); | BLO_read_data_address(reader, &ma->preview); | ||||
| BKE_previewimg_blend_read(reader, ma->preview); | BKE_previewimg_blend_read(reader, ma->preview); | ||||
| BLI_listbase_clear(&ma->gpumaterial); | BLI_listbase_clear(&ma->gpumaterial); | ||||
| BLO_read_data_address(reader, &ma->gp_style); | BLO_read_data_address(reader, &ma->gp_style); | ||||
| } | } | ||||
| static void material_blend_read_lib(BlendLibReader *reader, ID *id) | static void material_blend_read_lib(BlendLibReader *reader, ID *id) | ||||
| { | { | ||||
| Material *ma = (Material *)id; | Material *ma = (Material *)id; | ||||
| BLO_read_id_address(reader, ma->id.lib, &ma->ipo); /* XXX deprecated - old animation system */ | BLO_read_id_address(reader, ma->id.lib, &ma->ipo); /* XXX deprecated - old animation system */ | ||||
| /* relink grease pencil settings */ | /* relink grease pencil settings */ | ||||
| if (ma->gp_style != NULL) { | if (ma->gp_style != nullptr) { | ||||
| MaterialGPencilStyle *gp_style = ma->gp_style; | MaterialGPencilStyle *gp_style = ma->gp_style; | ||||
| if (gp_style->sima != NULL) { | if (gp_style->sima != nullptr) { | ||||
| BLO_read_id_address(reader, ma->id.lib, &gp_style->sima); | BLO_read_id_address(reader, ma->id.lib, &gp_style->sima); | ||||
| } | } | ||||
| if (gp_style->ima != NULL) { | if (gp_style->ima != nullptr) { | ||||
| BLO_read_id_address(reader, ma->id.lib, &gp_style->ima); | BLO_read_id_address(reader, ma->id.lib, &gp_style->ima); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void material_blend_read_expand(BlendExpander *expander, ID *id) | static void material_blend_read_expand(BlendExpander *expander, ID *id) | ||||
| { | { | ||||
| Material *ma = (Material *)id; | Material *ma = (Material *)id; | ||||
| Show All 10 Lines | IDTypeInfo IDType_ID_MA = { | ||||
| .id_code = ID_MA, | .id_code = ID_MA, | ||||
| .id_filter = FILTER_ID_MA, | .id_filter = FILTER_ID_MA, | ||||
| .main_listbase_index = INDEX_ID_MA, | .main_listbase_index = INDEX_ID_MA, | ||||
| .struct_size = sizeof(Material), | .struct_size = sizeof(Material), | ||||
| .name = "Material", | .name = "Material", | ||||
| .name_plural = "materials", | .name_plural = "materials", | ||||
| .translation_context = BLT_I18NCONTEXT_ID_MATERIAL, | .translation_context = BLT_I18NCONTEXT_ID_MATERIAL, | ||||
| .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, | .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, | ||||
| .asset_type_info = NULL, | .asset_type_info = nullptr, | ||||
| .init_data = material_init_data, | .init_data = material_init_data, | ||||
| .copy_data = material_copy_data, | .copy_data = material_copy_data, | ||||
| .free_data = material_free_data, | .free_data = material_free_data, | ||||
| .make_local = NULL, | .make_local = nullptr, | ||||
| .foreach_id = material_foreach_id, | .foreach_id = material_foreach_id, | ||||
| .foreach_cache = NULL, | .foreach_cache = nullptr, | ||||
| .foreach_path = NULL, | .foreach_path = nullptr, | ||||
| .owner_pointer_get = NULL, | .owner_pointer_get = nullptr, | ||||
| .blend_write = material_blend_write, | .blend_write = material_blend_write, | ||||
| .blend_read_data = material_blend_read_data, | .blend_read_data = material_blend_read_data, | ||||
| .blend_read_lib = material_blend_read_lib, | .blend_read_lib = material_blend_read_lib, | ||||
| .blend_read_expand = material_blend_read_expand, | .blend_read_expand = material_blend_read_expand, | ||||
| .blend_read_undo_preserve = NULL, | .blend_read_undo_preserve = nullptr, | ||||
| .lib_override_apply_post = NULL, | .lib_override_apply_post = nullptr, | ||||
| }; | }; | ||||
| void BKE_gpencil_material_attr_init(Material *ma) | void BKE_gpencil_material_attr_init(Material *ma) | ||||
| { | { | ||||
| if ((ma) && (ma->gp_style == NULL)) { | if ((ma) && (ma->gp_style == nullptr)) { | ||||
| ma->gp_style = MEM_callocN(sizeof(MaterialGPencilStyle), "Grease Pencil Material Settings"); | ma->gp_style = MEM_cnew<MaterialGPencilStyle>("Grease Pencil Material Settings"); | ||||
| MaterialGPencilStyle *gp_style = ma->gp_style; | MaterialGPencilStyle *gp_style = ma->gp_style; | ||||
| /* set basic settings */ | /* set basic settings */ | ||||
| gp_style->stroke_rgba[3] = 1.0f; | gp_style->stroke_rgba[3] = 1.0f; | ||||
| gp_style->fill_rgba[3] = 1.0f; | gp_style->fill_rgba[3] = 1.0f; | ||||
| ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 1.0f); | ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 1.0f); | ||||
| ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f); | ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f); | ||||
| gp_style->texture_offset[0] = -0.5f; | gp_style->texture_offset[0] = -0.5f; | ||||
| gp_style->texture_pixsize = 100.0f; | gp_style->texture_pixsize = 100.0f; | ||||
| gp_style->mix_factor = 0.5f; | gp_style->mix_factor = 0.5f; | ||||
| gp_style->flag |= GP_MATERIAL_STROKE_SHOW; | gp_style->flag |= GP_MATERIAL_STROKE_SHOW; | ||||
| } | } | ||||
| } | } | ||||
| Material *BKE_material_add(Main *bmain, const char *name) | Material *BKE_material_add(Main *bmain, const char *name) | ||||
| { | { | ||||
| Material *ma; | Material *ma; | ||||
| ma = BKE_id_new(bmain, ID_MA, name); | ma = static_cast<Material *>(BKE_id_new(bmain, ID_MA, name)); | ||||
| return ma; | return ma; | ||||
| } | } | ||||
| Material *BKE_gpencil_material_add(Main *bmain, const char *name) | Material *BKE_gpencil_material_add(Main *bmain, const char *name) | ||||
| { | { | ||||
| Material *ma; | Material *ma; | ||||
| ma = BKE_material_add(bmain, name); | ma = BKE_material_add(bmain, name); | ||||
| /* grease pencil settings */ | /* grease pencil settings */ | ||||
| if (ma != NULL) { | if (ma != nullptr) { | ||||
| BKE_gpencil_material_attr_init(ma); | BKE_gpencil_material_attr_init(ma); | ||||
| } | } | ||||
| return ma; | return ma; | ||||
| } | } | ||||
| Material ***BKE_object_material_array_p(Object *ob) | Material ***BKE_object_material_array_p(Object *ob) | ||||
| { | { | ||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| Mesh *me = ob->data; | Mesh *me = static_cast<Mesh *>(ob->data); | ||||
| return &(me->mat); | return &(me->mat); | ||||
| } | } | ||||
| if (ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { | if (ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { | ||||
| Curve *cu = ob->data; | Curve *cu = static_cast<Curve *>(ob->data); | ||||
| return &(cu->mat); | return &(cu->mat); | ||||
| } | } | ||||
| if (ob->type == OB_MBALL) { | if (ob->type == OB_MBALL) { | ||||
| MetaBall *mb = ob->data; | MetaBall *mb = static_cast<MetaBall *>(ob->data); | ||||
| return &(mb->mat); | return &(mb->mat); | ||||
| } | } | ||||
| if (ob->type == OB_GPENCIL) { | if (ob->type == OB_GPENCIL) { | ||||
| bGPdata *gpd = ob->data; | bGPdata *gpd = static_cast<bGPdata *>(ob->data); | ||||
| return &(gpd->mat); | return &(gpd->mat); | ||||
| } | } | ||||
| if (ob->type == OB_CURVES) { | if (ob->type == OB_CURVES) { | ||||
| Curves *curves = ob->data; | Curves *curves = static_cast<Curves *>(ob->data); | ||||
| return &(curves->mat); | return &(curves->mat); | ||||
| } | } | ||||
| if (ob->type == OB_POINTCLOUD) { | if (ob->type == OB_POINTCLOUD) { | ||||
| PointCloud *pointcloud = ob->data; | PointCloud *pointcloud = static_cast<PointCloud *>(ob->data); | ||||
| return &(pointcloud->mat); | return &(pointcloud->mat); | ||||
| } | } | ||||
| if (ob->type == OB_VOLUME) { | if (ob->type == OB_VOLUME) { | ||||
| Volume *volume = ob->data; | Volume *volume = static_cast<Volume *>(ob->data); | ||||
| return &(volume->mat); | return &(volume->mat); | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| short *BKE_object_material_len_p(Object *ob) | short *BKE_object_material_len_p(Object *ob) | ||||
| { | { | ||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| Mesh *me = ob->data; | Mesh *me = static_cast<Mesh *>(ob->data); | ||||
| return &(me->totcol); | return &(me->totcol); | ||||
| } | } | ||||
| if (ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { | if (ELEM(ob->type, OB_CURVES_LEGACY, OB_FONT, OB_SURF)) { | ||||
| Curve *cu = ob->data; | Curve *cu = static_cast<Curve *>(ob->data); | ||||
| return &(cu->totcol); | return &(cu->totcol); | ||||
| } | } | ||||
| if (ob->type == OB_MBALL) { | if (ob->type == OB_MBALL) { | ||||
| MetaBall *mb = ob->data; | MetaBall *mb = static_cast<MetaBall *>(ob->data); | ||||
| return &(mb->totcol); | return &(mb->totcol); | ||||
| } | } | ||||
| if (ob->type == OB_GPENCIL) { | if (ob->type == OB_GPENCIL) { | ||||
| bGPdata *gpd = ob->data; | bGPdata *gpd = static_cast<bGPdata *>(ob->data); | ||||
| return &(gpd->totcol); | return &(gpd->totcol); | ||||
| } | } | ||||
| if (ob->type == OB_CURVES) { | if (ob->type == OB_CURVES) { | ||||
| Curves *curves = ob->data; | Curves *curves = static_cast<Curves *>(ob->data); | ||||
| return &(curves->totcol); | return &(curves->totcol); | ||||
| } | } | ||||
| if (ob->type == OB_POINTCLOUD) { | if (ob->type == OB_POINTCLOUD) { | ||||
| PointCloud *pointcloud = ob->data; | PointCloud *pointcloud = static_cast<PointCloud *>(ob->data); | ||||
| return &(pointcloud->totcol); | return &(pointcloud->totcol); | ||||
| } | } | ||||
| if (ob->type == OB_VOLUME) { | if (ob->type == OB_VOLUME) { | ||||
| Volume *volume = ob->data; | Volume *volume = static_cast<Volume *>(ob->data); | ||||
| return &(volume->totcol); | return &(volume->totcol); | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| Material ***BKE_id_material_array_p(ID *id) | Material ***BKE_id_material_array_p(ID *id) | ||||
| { | { | ||||
| /* ensure we don't try get materials from non-obdata */ | /* ensure we don't try get materials from non-obdata */ | ||||
| BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); | BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); | ||||
| switch (GS(id->name)) { | switch (GS(id->name)) { | ||||
| Show All 9 Lines | case ID_CV: | ||||
| return &(((Curves *)id)->mat); | return &(((Curves *)id)->mat); | ||||
| case ID_PT: | case ID_PT: | ||||
| return &(((PointCloud *)id)->mat); | return &(((PointCloud *)id)->mat); | ||||
| case ID_VO: | case ID_VO: | ||||
| return &(((Volume *)id)->mat); | return &(((Volume *)id)->mat); | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| short *BKE_id_material_len_p(ID *id) | short *BKE_id_material_len_p(ID *id) | ||||
| { | { | ||||
| /* ensure we don't try get materials from non-obdata */ | /* ensure we don't try get materials from non-obdata */ | ||||
| BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); | BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); | ||||
| switch (GS(id->name)) { | switch (GS(id->name)) { | ||||
| Show All 9 Lines | case ID_CV: | ||||
| return &(((Curves *)id)->totcol); | return &(((Curves *)id)->totcol); | ||||
| case ID_PT: | case ID_PT: | ||||
| return &(((PointCloud *)id)->totcol); | return &(((PointCloud *)id)->totcol); | ||||
| case ID_VO: | case ID_VO: | ||||
| return &(((Volume *)id)->totcol); | return &(((Volume *)id)->totcol); | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| static void material_data_index_remove_id(ID *id, short index) | static void material_data_index_remove_id(ID *id, short index) | ||||
| { | { | ||||
| /* ensure we don't try get materials from non-obdata */ | /* ensure we don't try get materials from non-obdata */ | ||||
| BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); | BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name))); | ||||
| switch (GS(id->name)) { | switch (GS(id->name)) { | ||||
| Show All 21 Lines | bool BKE_object_material_slot_used(Object *object, short actcol) | ||||
| } | } | ||||
| LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { | LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { | ||||
| if (psys->part->omat == actcol) { | if (psys->part->omat == actcol) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| ID *ob_data = object->data; | ID *ob_data = static_cast<ID *>(object->data); | ||||
| if (ob_data == NULL || !OB_DATA_SUPPORT_ID(GS(ob_data->name))) { | if (ob_data == nullptr || !OB_DATA_SUPPORT_ID(GS(ob_data->name))) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| switch (GS(ob_data->name)) { | switch (GS(ob_data->name)) { | ||||
| case ID_ME: | case ID_ME: | ||||
| return BKE_mesh_material_index_used((Mesh *)ob_data, actcol - 1); | return BKE_mesh_material_index_used((Mesh *)ob_data, actcol - 1); | ||||
| case ID_CU_LEGACY: | case ID_CU_LEGACY: | ||||
| return BKE_curve_material_index_used((Curve *)ob_data, actcol - 1); | return BKE_curve_material_index_used((Curve *)ob_data, actcol - 1); | ||||
| Show All 35 Lines | void BKE_id_materials_copy(Main *bmain, ID *id_src, ID *id_dst) | ||||
| Material ***matar_src = BKE_id_material_array_p(id_src); | Material ***matar_src = BKE_id_material_array_p(id_src); | ||||
| const short *materials_len_p_src = BKE_id_material_len_p(id_src); | const short *materials_len_p_src = BKE_id_material_len_p(id_src); | ||||
| Material ***matar_dst = BKE_id_material_array_p(id_dst); | Material ***matar_dst = BKE_id_material_array_p(id_dst); | ||||
| short *materials_len_p_dst = BKE_id_material_len_p(id_dst); | short *materials_len_p_dst = BKE_id_material_len_p(id_dst); | ||||
| *materials_len_p_dst = *materials_len_p_src; | *materials_len_p_dst = *materials_len_p_src; | ||||
| if (*materials_len_p_src != 0) { | if (*materials_len_p_src != 0) { | ||||
| (*matar_dst) = MEM_dupallocN(*matar_src); | (*matar_dst) = static_cast<Material **>(MEM_dupallocN(*matar_src)); | ||||
| for (int a = 0; a < *materials_len_p_src; a++) { | for (int a = 0; a < *materials_len_p_src; a++) { | ||||
| id_us_plus((ID *)(*matar_dst)[a]); | id_us_plus((ID *)(*matar_dst)[a]); | ||||
| } | } | ||||
| DEG_id_tag_update(id_dst, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(id_dst, ID_RECALC_COPY_ON_WRITE); | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| } | } | ||||
| void BKE_id_material_resize(Main *bmain, ID *id, short totcol, bool do_id_user) | void BKE_id_material_resize(Main *bmain, ID *id, short totcol, bool do_id_user) | ||||
| { | { | ||||
| Material ***matar = BKE_id_material_array_p(id); | Material ***matar = BKE_id_material_array_p(id); | ||||
| short *totcolp = BKE_id_material_len_p(id); | short *totcolp = BKE_id_material_len_p(id); | ||||
| if (matar == NULL) { | if (matar == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (do_id_user && totcol < (*totcolp)) { | if (do_id_user && totcol < (*totcolp)) { | ||||
| short i; | short i; | ||||
| for (i = totcol; i < (*totcolp); i++) { | for (i = totcol; i < (*totcolp); i++) { | ||||
| id_us_min((ID *)(*matar)[i]); | id_us_min((ID *)(*matar)[i]); | ||||
| } | } | ||||
| } | } | ||||
| if (totcol == 0) { | if (totcol == 0) { | ||||
| if (*totcolp) { | if (*totcolp) { | ||||
| MEM_freeN(*matar); | MEM_freeN(*matar); | ||||
| *matar = NULL; | *matar = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| *matar = MEM_recallocN(*matar, sizeof(void *) * totcol); | *matar = static_cast<Material **>(MEM_recallocN(*matar, sizeof(void *) * totcol)); | ||||
| } | } | ||||
| *totcolp = totcol; | *totcolp = totcol; | ||||
| DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| void BKE_id_material_append(Main *bmain, ID *id, Material *ma) | void BKE_id_material_append(Main *bmain, ID *id, Material *ma) | ||||
| { | { | ||||
| Material ***matar; | Material ***matar; | ||||
| if ((matar = BKE_id_material_array_p(id))) { | if ((matar = BKE_id_material_array_p(id))) { | ||||
| short *totcol = BKE_id_material_len_p(id); | short *totcol = BKE_id_material_len_p(id); | ||||
| Material **mat = MEM_callocN(sizeof(void *) * ((*totcol) + 1), "newmatar"); | Material **mat = MEM_cnew_array<Material *>((*totcol) + 1, "newmatar"); | ||||
| if (*totcol) { | if (*totcol) { | ||||
| memcpy(mat, *matar, sizeof(void *) * (*totcol)); | memcpy(mat, *matar, sizeof(void *) * (*totcol)); | ||||
| } | } | ||||
| if (*matar) { | if (*matar) { | ||||
| MEM_freeN(*matar); | MEM_freeN(*matar); | ||||
| } | } | ||||
| *matar = mat; | *matar = mat; | ||||
| (*matar)[(*totcol)++] = ma; | (*matar)[(*totcol)++] = ma; | ||||
| id_us_plus((ID *)ma); | id_us_plus((ID *)ma); | ||||
| BKE_objects_materials_test_all(bmain, id); | BKE_objects_materials_test_all(bmain, id); | ||||
| DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| } | } | ||||
| Material *BKE_id_material_pop(Main *bmain, ID *id, int index_i) | Material *BKE_id_material_pop(Main *bmain, ID *id, int index_i) | ||||
| { | { | ||||
| short index = (short)index_i; | short index = (short)index_i; | ||||
| Material *ret = NULL; | Material *ret = nullptr; | ||||
| Material ***matar; | Material ***matar; | ||||
| if ((matar = BKE_id_material_array_p(id))) { | if ((matar = BKE_id_material_array_p(id))) { | ||||
| short *totcol = BKE_id_material_len_p(id); | short *totcol = BKE_id_material_len_p(id); | ||||
| if (index >= 0 && index < (*totcol)) { | if (index >= 0 && index < (*totcol)) { | ||||
| ret = (*matar)[index]; | ret = (*matar)[index]; | ||||
| id_us_min((ID *)ret); | id_us_min((ID *)ret); | ||||
| if (*totcol <= 1) { | if (*totcol <= 1) { | ||||
| *totcol = 0; | *totcol = 0; | ||||
| MEM_freeN(*matar); | MEM_freeN(*matar); | ||||
| *matar = NULL; | *matar = nullptr; | ||||
| } | } | ||||
| else { | else { | ||||
| if (index + 1 != (*totcol)) { | if (index + 1 != (*totcol)) { | ||||
| memmove((*matar) + index, | memmove((*matar) + index, | ||||
| (*matar) + (index + 1), | (*matar) + (index + 1), | ||||
| sizeof(void *) * ((*totcol) - (index + 1))); | sizeof(void *) * ((*totcol) - (index + 1))); | ||||
| } | } | ||||
| (*totcol)--; | (*totcol)--; | ||||
| *matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol)); | *matar = static_cast<Material **>(MEM_reallocN(*matar, sizeof(void *) * (*totcol))); | ||||
| BKE_objects_materials_test_all(bmain, id); | BKE_objects_materials_test_all(bmain, id); | ||||
| } | } | ||||
| material_data_index_remove_id(id, index); | material_data_index_remove_id(id, index); | ||||
| DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| Show All 9 Lines | if ((matar = BKE_id_material_array_p(id))) { | ||||
| short *totcol = BKE_id_material_len_p(id); | short *totcol = BKE_id_material_len_p(id); | ||||
| while ((*totcol)--) { | while ((*totcol)--) { | ||||
| id_us_min((ID *)((*matar)[*totcol])); | id_us_min((ID *)((*matar)[*totcol])); | ||||
| } | } | ||||
| *totcol = 0; | *totcol = 0; | ||||
| if (*matar) { | if (*matar) { | ||||
| MEM_freeN(*matar); | MEM_freeN(*matar); | ||||
| *matar = NULL; | *matar = nullptr; | ||||
| } | } | ||||
| BKE_objects_materials_test_all(bmain, id); | BKE_objects_materials_test_all(bmain, id); | ||||
| material_data_index_clear_id(id); | material_data_index_clear_id(id); | ||||
| DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | DEG_id_tag_update(id, ID_RECALC_COPY_ON_WRITE); | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| } | } | ||||
| Material **BKE_object_material_get_p(Object *ob, short act) | Material **BKE_object_material_get_p(Object *ob, short act) | ||||
| { | { | ||||
| Material ***matarar, **ma_p; | Material ***matarar, **ma_p; | ||||
| const short *totcolp; | const short *totcolp; | ||||
| if (ob == NULL) { | if (ob == nullptr) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* if object cannot have material, (totcolp == NULL) */ | /* if object cannot have material, (totcolp == nullptr) */ | ||||
| totcolp = BKE_object_material_len_p(ob); | totcolp = BKE_object_material_len_p(ob); | ||||
| if (totcolp == NULL || *totcolp == 0) { | if (totcolp == nullptr || *totcolp == 0) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* Clamp to number of slots if index is out of range, same convention as used for rendering. */ | /* Clamp to number of slots if index is out of range, same convention as used for rendering. */ | ||||
| const int slot_index = clamp_i(act - 1, 0, *totcolp - 1); | const int slot_index = clamp_i(act - 1, 0, *totcolp - 1); | ||||
| /* Fix inconsistency which may happen when library linked data reduces the number of | /* Fix inconsistency which may happen when library linked data reduces the number of | ||||
| * slots but object was not updated. Ideally should be fixed elsewhere. */ | * slots but object was not updated. Ideally should be fixed elsewhere. */ | ||||
| if (*totcolp < ob->totcol) { | if (*totcolp < ob->totcol) { | ||||
| ob->totcol = *totcolp; | ob->totcol = *totcolp; | ||||
| } | } | ||||
| if (slot_index < ob->totcol && ob->matbits && ob->matbits[slot_index]) { | if (slot_index < ob->totcol && ob->matbits && ob->matbits[slot_index]) { | ||||
| /* Use object material slot. */ | /* Use object material slot. */ | ||||
| ma_p = &ob->mat[slot_index]; | ma_p = &ob->mat[slot_index]; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Use data material slot. */ | /* Use data material slot. */ | ||||
| matarar = BKE_object_material_array_p(ob); | matarar = BKE_object_material_array_p(ob); | ||||
| if (matarar && *matarar) { | if (matarar && *matarar) { | ||||
| ma_p = &(*matarar)[slot_index]; | ma_p = &(*matarar)[slot_index]; | ||||
| } | } | ||||
| else { | else { | ||||
| ma_p = NULL; | ma_p = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| return ma_p; | return ma_p; | ||||
| } | } | ||||
| Material *BKE_object_material_get(Object *ob, short act) | Material *BKE_object_material_get(Object *ob, short act) | ||||
| { | { | ||||
| Material **ma_p = BKE_object_material_get_p(ob, act); | Material **ma_p = BKE_object_material_get_p(ob, act); | ||||
| return ma_p ? *ma_p : NULL; | return ma_p ? *ma_p : nullptr; | ||||
| } | } | ||||
| static ID *get_evaluated_object_data_with_materials(Object *ob) | static ID *get_evaluated_object_data_with_materials(Object *ob) | ||||
| { | { | ||||
| ID *data = ob->data; | ID *data = static_cast<ID *>(ob->data); | ||||
| /* Meshes in edit mode need special handling. */ | /* Meshes in edit mode need special handling. */ | ||||
| if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) { | if (ob->type == OB_MESH && ob->mode == OB_MODE_EDIT) { | ||||
| Mesh *mesh = ob->data; | Mesh *mesh = static_cast<Mesh *>(ob->data); | ||||
| Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); | Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob); | ||||
| if (mesh->edit_mesh && editmesh_eval_final) { | if (mesh->edit_mesh && editmesh_eval_final) { | ||||
| data = &editmesh_eval_final->id; | data = &editmesh_eval_final->id; | ||||
| } | } | ||||
| } | } | ||||
| return data; | return data; | ||||
| } | } | ||||
| Material *BKE_object_material_get_eval(Object *ob, short act) | Material *BKE_object_material_get_eval(Object *ob, short act) | ||||
| { | { | ||||
| BLI_assert(DEG_is_evaluated_object(ob)); | BLI_assert(DEG_is_evaluated_object(ob)); | ||||
| ID *data = get_evaluated_object_data_with_materials(ob); | ID *data = get_evaluated_object_data_with_materials(ob); | ||||
| const short *tot_slots_data_ptr = BKE_id_material_len_p(data); | const short *tot_slots_data_ptr = BKE_id_material_len_p(data); | ||||
| const int tot_slots_data = tot_slots_data_ptr ? *tot_slots_data_ptr : 0; | const int tot_slots_data = tot_slots_data_ptr ? *tot_slots_data_ptr : 0; | ||||
| if (tot_slots_data == 0) { | if (tot_slots_data == 0) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /* Clamp to number of slots if index is out of range, same convention as used for rendering. */ | /* Clamp to number of slots if index is out of range, same convention as used for rendering. */ | ||||
| const int slot_index = clamp_i(act - 1, 0, tot_slots_data - 1); | const int slot_index = clamp_i(act - 1, 0, tot_slots_data - 1); | ||||
| const int tot_slots_object = ob->totcol; | const int tot_slots_object = ob->totcol; | ||||
| Material ***materials_data_ptr = BKE_id_material_array_p(data); | Material ***materials_data_ptr = BKE_id_material_array_p(data); | ||||
| Material **materials_data = materials_data_ptr ? *materials_data_ptr : NULL; | Material **materials_data = materials_data_ptr ? *materials_data_ptr : nullptr; | ||||
| Material **materials_object = ob->mat; | Material **materials_object = ob->mat; | ||||
| /* Check if slot is overwritten by object. */ | /* Check if slot is overwritten by object. */ | ||||
| if (slot_index < tot_slots_object) { | if (slot_index < tot_slots_object) { | ||||
| if (ob->matbits) { | if (ob->matbits) { | ||||
| if (ob->matbits[slot_index]) { | if (ob->matbits[slot_index]) { | ||||
| Material *material = materials_object[slot_index]; | Material *material = materials_object[slot_index]; | ||||
| if (material != NULL) { | if (material != nullptr) { | ||||
| return material; | return material; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Otherwise use data from object-data. */ | /* Otherwise use data from object-data. */ | ||||
| if (slot_index < tot_slots_data) { | if (slot_index < tot_slots_data) { | ||||
| Material *material = materials_data[slot_index]; | Material *material = materials_data[slot_index]; | ||||
| return material; | return material; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| int BKE_object_material_count_eval(Object *ob) | int BKE_object_material_count_eval(Object *ob) | ||||
| { | { | ||||
| BLI_assert(DEG_is_evaluated_object(ob)); | BLI_assert(DEG_is_evaluated_object(ob)); | ||||
| ID *id = get_evaluated_object_data_with_materials(ob); | ID *id = get_evaluated_object_data_with_materials(ob); | ||||
| const short *len_p = BKE_id_material_len_p(id); | const short *len_p = BKE_id_material_len_p(id); | ||||
| return len_p ? *len_p : 0; | return len_p ? *len_p : 0; | ||||
| } | } | ||||
| void BKE_id_material_eval_assign(ID *id, int slot, Material *material) | void BKE_id_material_eval_assign(ID *id, int slot, Material *material) | ||||
| { | { | ||||
| BLI_assert(slot >= 1); | BLI_assert(slot >= 1); | ||||
| Material ***materials_ptr = BKE_id_material_array_p(id); | Material ***materials_ptr = BKE_id_material_array_p(id); | ||||
| short *len_ptr = BKE_id_material_len_p(id); | short *len_ptr = BKE_id_material_len_p(id); | ||||
| if (ELEM(NULL, materials_ptr, len_ptr)) { | if (ELEM(nullptr, materials_ptr, len_ptr)) { | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| return; | return; | ||||
| } | } | ||||
| const int slot_index = slot - 1; | const int slot_index = slot - 1; | ||||
| const int old_length = *len_ptr; | const int old_length = *len_ptr; | ||||
| if (slot_index >= old_length) { | if (slot_index >= old_length) { | ||||
| /* Need to grow slots array. */ | /* Need to grow slots array. */ | ||||
| const int new_length = slot_index + 1; | const int new_length = slot_index + 1; | ||||
| *materials_ptr = MEM_reallocN(*materials_ptr, sizeof(void *) * new_length); | *materials_ptr = static_cast<Material **>( | ||||
| MEM_reallocN(*materials_ptr, sizeof(void *) * new_length)); | |||||
| *len_ptr = new_length; | *len_ptr = new_length; | ||||
| for (int i = old_length; i < new_length; i++) { | for (int i = old_length; i < new_length; i++) { | ||||
| (*materials_ptr)[i] = NULL; | (*materials_ptr)[i] = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| (*materials_ptr)[slot_index] = material; | (*materials_ptr)[slot_index] = material; | ||||
| } | } | ||||
| void BKE_id_material_eval_ensure_default_slot(ID *id) | void BKE_id_material_eval_ensure_default_slot(ID *id) | ||||
| { | { | ||||
| short *len_ptr = BKE_id_material_len_p(id); | short *len_ptr = BKE_id_material_len_p(id); | ||||
| if (len_ptr == NULL) { | if (len_ptr == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (*len_ptr == 0) { | if (*len_ptr == 0) { | ||||
| BKE_id_material_eval_assign(id, 1, NULL); | BKE_id_material_eval_assign(id, 1, nullptr); | ||||
| } | } | ||||
| } | } | ||||
| Material *BKE_gpencil_material(Object *ob, short act) | Material *BKE_gpencil_material(Object *ob, short act) | ||||
| { | { | ||||
| Material *ma = BKE_object_material_get(ob, act); | Material *ma = BKE_object_material_get(ob, act); | ||||
| if (ma != NULL) { | if (ma != nullptr) { | ||||
| return ma; | return ma; | ||||
| } | } | ||||
| return BKE_material_default_gpencil(); | return BKE_material_default_gpencil(); | ||||
| } | } | ||||
| MaterialGPencilStyle *BKE_gpencil_material_settings(Object *ob, short act) | MaterialGPencilStyle *BKE_gpencil_material_settings(Object *ob, short act) | ||||
| { | { | ||||
| Material *ma = BKE_object_material_get(ob, act); | Material *ma = BKE_object_material_get(ob, act); | ||||
| if (ma != NULL) { | if (ma != nullptr) { | ||||
| if (ma->gp_style == NULL) { | if (ma->gp_style == nullptr) { | ||||
| BKE_gpencil_material_attr_init(ma); | BKE_gpencil_material_attr_init(ma); | ||||
| } | } | ||||
| return ma->gp_style; | return ma->gp_style; | ||||
| } | } | ||||
| return BKE_material_default_gpencil()->gp_style; | return BKE_material_default_gpencil()->gp_style; | ||||
| } | } | ||||
| void BKE_object_material_resize(Main *bmain, Object *ob, const short totcol, bool do_id_user) | void BKE_object_material_resize(Main *bmain, Object *ob, const short totcol, bool do_id_user) | ||||
| { | { | ||||
| Material **newmatar; | Material **newmatar; | ||||
| char *newmatbits; | char *newmatbits; | ||||
| if (do_id_user && totcol < ob->totcol) { | if (do_id_user && totcol < ob->totcol) { | ||||
| for (int i = totcol; i < ob->totcol; i++) { | for (int i = totcol; i < ob->totcol; i++) { | ||||
| id_us_min((ID *)ob->mat[i]); | id_us_min((ID *)ob->mat[i]); | ||||
| } | } | ||||
| } | } | ||||
| if (totcol == 0) { | if (totcol == 0) { | ||||
| if (ob->totcol) { | if (ob->totcol) { | ||||
| MEM_freeN(ob->mat); | MEM_freeN(ob->mat); | ||||
| MEM_freeN(ob->matbits); | MEM_freeN(ob->matbits); | ||||
| ob->mat = NULL; | ob->mat = nullptr; | ||||
| ob->matbits = NULL; | ob->matbits = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| else if (ob->totcol < totcol) { | else if (ob->totcol < totcol) { | ||||
| newmatar = MEM_callocN(sizeof(void *) * totcol, "newmatar"); | newmatar = MEM_cnew_array<Material *>(totcol, "newmatar"); | ||||
| newmatbits = MEM_callocN(sizeof(char) * totcol, "newmatbits"); | newmatbits = MEM_cnew_array<char>(totcol, "newmatbits"); | ||||
| if (ob->totcol) { | if (ob->totcol) { | ||||
| memcpy(newmatar, ob->mat, sizeof(void *) * ob->totcol); | memcpy(newmatar, ob->mat, sizeof(void *) * ob->totcol); | ||||
| memcpy(newmatbits, ob->matbits, sizeof(char) * ob->totcol); | memcpy(newmatbits, ob->matbits, sizeof(char) * ob->totcol); | ||||
| MEM_freeN(ob->mat); | MEM_freeN(ob->mat); | ||||
| MEM_freeN(ob->matbits); | MEM_freeN(ob->matbits); | ||||
| } | } | ||||
| ob->mat = newmatar; | ob->mat = newmatar; | ||||
| ob->matbits = newmatbits; | ob->matbits = newmatbits; | ||||
| Show All 12 Lines | void BKE_object_material_resize(Main *bmain, Object *ob, const short totcol, bool do_id_user) | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| void BKE_object_materials_test(Main *bmain, Object *ob, ID *id) | void BKE_object_materials_test(Main *bmain, Object *ob, ID *id) | ||||
| { | { | ||||
| /* make the ob mat-array same size as 'ob->data' mat-array */ | /* make the ob mat-array same size as 'ob->data' mat-array */ | ||||
| const short *totcol; | const short *totcol; | ||||
| if (id == NULL || (totcol = BKE_id_material_len_p(id)) == NULL) { | if (id == nullptr || (totcol = BKE_id_material_len_p(id)) == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if ((ob->id.tag & LIB_TAG_MISSING) == 0 && (id->tag & LIB_TAG_MISSING) != 0) { | if ((ob->id.tag & LIB_TAG_MISSING) == 0 && (id->tag & LIB_TAG_MISSING) != 0) { | ||||
| /* Exception: In case the object is a valid data, but its obdata is an empty place-holder, | /* Exception: In case the object is a valid data, but its obdata is an empty place-holder, | ||||
| * use object's material slots amount as reference. | * use object's material slots amount as reference. | ||||
| * This avoids losing materials in a local object when its linked obdata goes missing. | * This avoids losing materials in a local object when its linked obdata goes missing. | ||||
| * See T92780. */ | * See T92780. */ | ||||
| BKE_id_material_resize(bmain, id, (short)ob->totcol, false); | BKE_id_material_resize(bmain, id, (short)ob->totcol, false); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Normal case: the use the obdata amount of materials slots to update the object's one. */ | /* Normal case: the use the obdata amount of materials slots to update the object's one. */ | ||||
| BKE_object_material_resize(bmain, ob, *totcol, false); | BKE_object_material_resize(bmain, ob, *totcol, false); | ||||
| } | } | ||||
| } | } | ||||
| void BKE_objects_materials_test_all(Main *bmain, ID *id) | void BKE_objects_materials_test_all(Main *bmain, ID *id) | ||||
| { | { | ||||
| /* make the ob mat-array same size as 'ob->data' mat-array */ | /* make the ob mat-array same size as 'ob->data' mat-array */ | ||||
| Object *ob; | Object *ob; | ||||
| const short *totcol; | const short *totcol; | ||||
| if (id == NULL || (totcol = BKE_id_material_len_p(id)) == NULL) { | if (id == nullptr || (totcol = BKE_id_material_len_p(id)) == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| BKE_main_lock(bmain); | BKE_main_lock(bmain); | ||||
| int processed_objects = 0; | int processed_objects = 0; | ||||
| for (ob = bmain->objects.first; ob; ob = ob->id.next) { | for (ob = static_cast<Object *>(bmain->objects.first); ob; | ||||
| ob = static_cast<Object *>(ob->id.next)) { | |||||
| if (ob->data == id) { | if (ob->data == id) { | ||||
| BKE_object_material_resize(bmain, ob, *totcol, false); | BKE_object_material_resize(bmain, ob, *totcol, false); | ||||
| processed_objects++; | processed_objects++; | ||||
| BLI_assert(processed_objects <= id->us && processed_objects > 0); | BLI_assert(processed_objects <= id->us && processed_objects > 0); | ||||
| if (processed_objects == id->us) { | if (processed_objects == id->us) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| Show All 13 Lines | if (act < 1) { | ||||
| act = 1; | act = 1; | ||||
| } | } | ||||
| /* test arraylens */ | /* test arraylens */ | ||||
| totcolp = BKE_id_material_len_p(id); | totcolp = BKE_id_material_len_p(id); | ||||
| matarar = BKE_id_material_array_p(id); | matarar = BKE_id_material_array_p(id); | ||||
| if (totcolp == NULL || matarar == NULL) { | if (totcolp == nullptr || matarar == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (act > *totcolp) { | if (act > *totcolp) { | ||||
| matar = MEM_callocN(sizeof(void *) * act, "matarray1"); | matar = MEM_cnew_array<Material *>(act, "matarray1"); | ||||
| if (*totcolp) { | if (*totcolp) { | ||||
| memcpy(matar, *matarar, sizeof(void *) * (*totcolp)); | memcpy(matar, *matarar, sizeof(void *) * (*totcolp)); | ||||
| MEM_freeN(*matarar); | MEM_freeN(*matarar); | ||||
| } | } | ||||
| *matarar = matar; | *matarar = matar; | ||||
| *totcolp = act; | *totcolp = act; | ||||
| Show All 27 Lines | if (act < 1) { | ||||
| act = 1; | act = 1; | ||||
| } | } | ||||
| /* test arraylens */ | /* test arraylens */ | ||||
| totcolp = BKE_object_material_len_p(ob); | totcolp = BKE_object_material_len_p(ob); | ||||
| matarar = BKE_object_material_array_p(ob); | matarar = BKE_object_material_array_p(ob); | ||||
| if (totcolp == NULL || matarar == NULL) { | if (totcolp == nullptr || matarar == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (act > *totcolp) { | if (act > *totcolp) { | ||||
| matar = MEM_callocN(sizeof(void *) * act, "matarray1"); | matar = MEM_cnew_array<Material *>(act, "matarray1"); | ||||
| if (*totcolp) { | if (*totcolp) { | ||||
| memcpy(matar, *matarar, sizeof(void *) * (*totcolp)); | memcpy(matar, *matarar, sizeof(void *) * (*totcolp)); | ||||
| MEM_freeN(*matarar); | MEM_freeN(*matarar); | ||||
| } | } | ||||
| *matarar = matar; | *matarar = matar; | ||||
| *totcolp = act; | *totcolp = act; | ||||
| } | } | ||||
| if (act > ob->totcol) { | if (act > ob->totcol) { | ||||
| /* Need more space in the material arrays */ | /* Need more space in the material arrays */ | ||||
| ob->mat = MEM_recallocN_id(ob->mat, sizeof(void *) * act, "matarray2"); | ob->mat = static_cast<Material **>( | ||||
| ob->matbits = MEM_recallocN_id(ob->matbits, sizeof(char) * act, "matbits1"); | MEM_recallocN_id(ob->mat, sizeof(void *) * act, "matarray2")); | ||||
| ob->matbits = static_cast<char *>( | |||||
| MEM_recallocN_id(ob->matbits, sizeof(char) * act, "matbits1")); | |||||
| ob->totcol = act; | ob->totcol = act; | ||||
| } | } | ||||
| /* Determine the object/mesh linking */ | /* Determine the object/mesh linking */ | ||||
| if (assign_type == BKE_MAT_ASSIGN_EXISTING) { | if (assign_type == BKE_MAT_ASSIGN_EXISTING) { | ||||
| /* keep existing option (avoid confusion in scripts), | /* keep existing option (avoid confusion in scripts), | ||||
| * intentionally ignore userpref (default to obdata). */ | * intentionally ignore userpref (default to obdata). */ | ||||
| bit = ob->matbits[act - 1]; | bit = ob->matbits[act - 1]; | ||||
| Show All 21 Lines | static void object_material_assign( | ||||
| ob->matbits[act - 1] = bit; | ob->matbits[act - 1] = bit; | ||||
| if (bit == 1) { /* in object */ | if (bit == 1) { /* in object */ | ||||
| mao = ob->mat[act - 1]; | mao = ob->mat[act - 1]; | ||||
| if (mao) { | if (mao) { | ||||
| id_us_min(&mao->id); | id_us_min(&mao->id); | ||||
| } | } | ||||
| ob->mat[act - 1] = ma; | ob->mat[act - 1] = ma; | ||||
| BKE_object_materials_test(bmain, ob, ob->data); | BKE_object_materials_test(bmain, ob, static_cast<ID *>(ob->data)); | ||||
| } | } | ||||
| else { /* in data */ | else { /* in data */ | ||||
| mao = (*matarar)[act - 1]; | mao = (*matarar)[act - 1]; | ||||
| if (mao) { | if (mao) { | ||||
| id_us_min(&mao->id); | id_us_min(&mao->id); | ||||
| } | } | ||||
| (*matarar)[act - 1] = ma; | (*matarar)[act - 1] = ma; | ||||
| /* Data may be used by several objects. */ | /* Data may be used by several objects. */ | ||||
| if (do_test_all) { | if (do_test_all) { | ||||
| BKE_objects_materials_test_all(bmain, ob->data); | BKE_objects_materials_test_all(bmain, static_cast<ID *>(ob->data)); | ||||
| } | } | ||||
| } | } | ||||
| if (ma) { | if (ma) { | ||||
| id_us_plus(&ma->id); | id_us_plus(&ma->id); | ||||
| } | } | ||||
| } | } | ||||
| Show All 21 Lines | if (ob->matbits) { | ||||
| BLI_array_permute(ob->matbits, ob->totcol, remap); | BLI_array_permute(ob->matbits, ob->totcol, remap); | ||||
| } | } | ||||
| if (matar) { | if (matar) { | ||||
| BLI_array_permute(*matar, *totcol_p, remap); | BLI_array_permute(*matar, *totcol_p, remap); | ||||
| } | } | ||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| BKE_mesh_material_remap(ob->data, remap, ob->totcol); | BKE_mesh_material_remap(static_cast<Mesh *>(ob->data), remap, ob->totcol); | ||||
| } | } | ||||
| else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { | else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { | ||||
| BKE_curve_material_remap(ob->data, remap, ob->totcol); | BKE_curve_material_remap(static_cast<Curve *>(ob->data), remap, ob->totcol); | ||||
| } | } | ||||
| else if (ob->type == OB_GPENCIL) { | else if (ob->type == OB_GPENCIL) { | ||||
| BKE_gpencil_material_remap(ob->data, remap, ob->totcol); | BKE_gpencil_material_remap(static_cast<bGPdata *>(ob->data), remap, ob->totcol); | ||||
| } | } | ||||
| else { | else { | ||||
| /* add support for this object data! */ | /* add support for this object data! */ | ||||
| BLI_assert(matar == NULL); | BLI_assert(matar == nullptr); | ||||
| } | } | ||||
| } | } | ||||
| void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst) | void BKE_object_material_remap_calc(Object *ob_dst, Object *ob_src, short *remap_src_to_dst) | ||||
| { | { | ||||
| if (ob_src->totcol == 0) { | if (ob_src->totcol == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| GHash *gh_mat_map = BLI_ghash_ptr_new_ex(__func__, ob_src->totcol); | GHash *gh_mat_map = BLI_ghash_ptr_new_ex(__func__, ob_src->totcol); | ||||
| for (int i = 0; i < ob_dst->totcol; i++) { | for (int i = 0; i < ob_dst->totcol; i++) { | ||||
| Material *ma_src = BKE_object_material_get(ob_dst, i + 1); | Material *ma_src = BKE_object_material_get(ob_dst, i + 1); | ||||
| BLI_ghash_reinsert(gh_mat_map, ma_src, POINTER_FROM_INT(i), NULL, NULL); | BLI_ghash_reinsert(gh_mat_map, ma_src, POINTER_FROM_INT(i), nullptr, nullptr); | ||||
| } | } | ||||
| /* setup default mapping (when materials don't match) */ | /* setup default mapping (when materials don't match) */ | ||||
| { | { | ||||
| int i = 0; | int i = 0; | ||||
| if (ob_dst->totcol >= ob_src->totcol) { | if (ob_dst->totcol >= ob_src->totcol) { | ||||
| for (; i < ob_src->totcol; i++) { | for (; i < ob_src->totcol; i++) { | ||||
| remap_src_to_dst[i] = i; | remap_src_to_dst[i] = i; | ||||
| Show All 18 Lines | for (int i = 0; i < ob_src->totcol; i++) { | ||||
| else { | else { | ||||
| void **index_src_p = BLI_ghash_lookup_p(gh_mat_map, ma_src); | void **index_src_p = BLI_ghash_lookup_p(gh_mat_map, ma_src); | ||||
| if (index_src_p) { | if (index_src_p) { | ||||
| remap_src_to_dst[i] = POINTER_AS_INT(*index_src_p); | remap_src_to_dst[i] = POINTER_AS_INT(*index_src_p); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| BLI_ghash_free(gh_mat_map, NULL, NULL); | BLI_ghash_free(gh_mat_map, nullptr, nullptr); | ||||
| } | } | ||||
| void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, const ID *data_eval) | void BKE_object_material_from_eval_data(Main *bmain, Object *ob_orig, const ID *data_eval) | ||||
| { | { | ||||
| ID *data_orig = ob_orig->data; | ID *data_orig = static_cast<ID *>(ob_orig->data); | ||||
| short *orig_totcol = BKE_id_material_len_p(data_orig); | short *orig_totcol = BKE_id_material_len_p(data_orig); | ||||
| Material ***orig_mat = BKE_id_material_array_p(data_orig); | Material ***orig_mat = BKE_id_material_array_p(data_orig); | ||||
| /* Can cast away const, because the data is not changed. */ | /* Can cast away const, because the data is not changed. */ | ||||
| const short *eval_totcol = BKE_id_material_len_p((ID *)data_eval); | const short *eval_totcol = BKE_id_material_len_p((ID *)data_eval); | ||||
| Material ***eval_mat = BKE_id_material_array_p((ID *)data_eval); | Material ***eval_mat = BKE_id_material_array_p((ID *)data_eval); | ||||
| if (ELEM(NULL, orig_totcol, orig_mat, eval_totcol, eval_mat)) { | if (ELEM(nullptr, orig_totcol, orig_mat, eval_totcol, eval_mat)) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Remove old materials from original geometry. */ | /* Remove old materials from original geometry. */ | ||||
| for (int i = 0; i < *orig_totcol; i++) { | for (int i = 0; i < *orig_totcol; i++) { | ||||
| id_us_min(&(*orig_mat)[i]->id); | id_us_min(&(*orig_mat)[i]->id); | ||||
| } | } | ||||
| MEM_SAFE_FREE(*orig_mat); | MEM_SAFE_FREE(*orig_mat); | ||||
| /* Create new material slots based on materials on evaluated geometry. */ | /* Create new material slots based on materials on evaluated geometry. */ | ||||
| *orig_totcol = *eval_totcol; | *orig_totcol = *eval_totcol; | ||||
| *orig_mat = MEM_callocN(sizeof(void *) * (*eval_totcol), __func__); | *orig_mat = MEM_cnew_array<Material *>(*eval_totcol, __func__); | ||||
| for (int i = 0; i < *eval_totcol; i++) { | for (int i = 0; i < *eval_totcol; i++) { | ||||
| Material *material_eval = (*eval_mat)[i]; | Material *material_eval = (*eval_mat)[i]; | ||||
| if (material_eval != NULL) { | if (material_eval != nullptr) { | ||||
| Material *material_orig = (Material *)DEG_get_original_id(&material_eval->id); | Material *material_orig = (Material *)DEG_get_original_id(&material_eval->id); | ||||
| (*orig_mat)[i] = material_orig; | (*orig_mat)[i] = material_orig; | ||||
| id_us_plus(&material_orig->id); | id_us_plus(&material_orig->id); | ||||
| } | } | ||||
| } | } | ||||
| BKE_object_materials_test(bmain, ob_orig, data_orig); | BKE_object_materials_test(bmain, ob_orig, data_orig); | ||||
| } | } | ||||
| Show All 29 Lines | void BKE_object_material_array_assign(Main *bmain, | ||||
| ob->actcol = actcol_orig; | ob->actcol = actcol_orig; | ||||
| } | } | ||||
| short BKE_object_material_slot_find_index(Object *ob, Material *ma) | short BKE_object_material_slot_find_index(Object *ob, Material *ma) | ||||
| { | { | ||||
| Material ***matarar; | Material ***matarar; | ||||
| short a, *totcolp; | short a, *totcolp; | ||||
| if (ma == NULL) { | if (ma == nullptr) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| totcolp = BKE_object_material_len_p(ob); | totcolp = BKE_object_material_len_p(ob); | ||||
| matarar = BKE_object_material_array_p(ob); | matarar = BKE_object_material_array_p(ob); | ||||
| if (totcolp == NULL || matarar == NULL) { | if (totcolp == nullptr || matarar == nullptr) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| for (a = 0; a < *totcolp; a++) { | for (a = 0; a < *totcolp; a++) { | ||||
| if ((*matarar)[a] == ma) { | if ((*matarar)[a] == ma) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (a < *totcolp) { | if (a < *totcolp) { | ||||
| return a + 1; | return a + 1; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| bool BKE_object_material_slot_add(Main *bmain, Object *ob) | bool BKE_object_material_slot_add(Main *bmain, Object *ob) | ||||
| { | { | ||||
| if (ob == NULL) { | if (ob == nullptr) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (ob->totcol >= MAXMAT) { | if (ob->totcol >= MAXMAT) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| BKE_object_material_assign(bmain, ob, NULL, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); | BKE_object_material_assign(bmain, ob, nullptr, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); | ||||
| ob->actcol = ob->totcol; | ob->actcol = ob->totcol; | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* ****************** */ | /* ****************** */ | ||||
| bool BKE_object_material_slot_remove(Main *bmain, Object *ob) | bool BKE_object_material_slot_remove(Main *bmain, Object *ob) | ||||
| { | { | ||||
| Material *mao, ***matarar; | Material *mao, ***matarar; | ||||
| short *totcolp; | short *totcolp; | ||||
| if (ob == NULL || ob->totcol == 0) { | if (ob == nullptr || ob->totcol == 0) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* this should never happen and used to crash */ | /* this should never happen and used to crash */ | ||||
| if (ob->actcol <= 0) { | if (ob->actcol <= 0) { | ||||
| CLOG_ERROR(&LOG, "invalid material index %d, report a bug!", ob->actcol); | CLOG_ERROR(&LOG, "invalid material index %d, report a bug!", ob->actcol); | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* take a mesh/curve/mball as starting point, remove 1 index, | /* take a mesh/curve/mball as starting point, remove 1 index, | ||||
| * AND with all objects that share the ob->data | * AND with all objects that share the ob->data | ||||
| * | * | ||||
| * after that check indices in mesh/curve/mball!!! | * after that check indices in mesh/curve/mball!!! | ||||
| */ | */ | ||||
| totcolp = BKE_object_material_len_p(ob); | totcolp = BKE_object_material_len_p(ob); | ||||
| matarar = BKE_object_material_array_p(ob); | matarar = BKE_object_material_array_p(ob); | ||||
| if (ELEM(NULL, matarar, *matarar)) { | if (ELEM(nullptr, matarar, *matarar)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* can happen on face selection in editmode */ | /* can happen on face selection in editmode */ | ||||
| if (ob->actcol > ob->totcol) { | if (ob->actcol > ob->totcol) { | ||||
| ob->actcol = ob->totcol; | ob->actcol = ob->totcol; | ||||
| } | } | ||||
| /* we delete the actcol */ | /* we delete the actcol */ | ||||
| mao = (*matarar)[ob->actcol - 1]; | mao = (*matarar)[ob->actcol - 1]; | ||||
| if (mao) { | if (mao) { | ||||
| id_us_min(&mao->id); | id_us_min(&mao->id); | ||||
| } | } | ||||
| for (int a = ob->actcol; a < ob->totcol; a++) { | for (int a = ob->actcol; a < ob->totcol; a++) { | ||||
| (*matarar)[a - 1] = (*matarar)[a]; | (*matarar)[a - 1] = (*matarar)[a]; | ||||
| } | } | ||||
| (*totcolp)--; | (*totcolp)--; | ||||
| if (*totcolp == 0) { | if (*totcolp == 0) { | ||||
| MEM_freeN(*matarar); | MEM_freeN(*matarar); | ||||
| *matarar = NULL; | *matarar = nullptr; | ||||
| } | } | ||||
| const int actcol = ob->actcol; | const int actcol = ob->actcol; | ||||
| for (Object *obt = bmain->objects.first; obt; obt = obt->id.next) { | for (Object *obt = static_cast<Object *>(bmain->objects.first); obt; | ||||
| obt = static_cast<Object *>(obt->id.next)) { | |||||
| if (obt->data == ob->data) { | if (obt->data == ob->data) { | ||||
| /* Can happen when object material lists are used, see: T52953 */ | /* Can happen when object material lists are used, see: T52953 */ | ||||
| if (actcol > obt->totcol) { | if (actcol > obt->totcol) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* WATCH IT: do not use actcol from ob or from obt (can become zero) */ | /* WATCH IT: do not use actcol from ob or from obt (can become zero) */ | ||||
| mao = obt->mat[actcol - 1]; | mao = obt->mat[actcol - 1]; | ||||
| if (mao) { | if (mao) { | ||||
| id_us_min(&mao->id); | id_us_min(&mao->id); | ||||
| } | } | ||||
| for (int a = actcol; a < obt->totcol; a++) { | for (int a = actcol; a < obt->totcol; a++) { | ||||
| obt->mat[a - 1] = obt->mat[a]; | obt->mat[a - 1] = obt->mat[a]; | ||||
| obt->matbits[a - 1] = obt->matbits[a]; | obt->matbits[a - 1] = obt->matbits[a]; | ||||
| } | } | ||||
| obt->totcol--; | obt->totcol--; | ||||
| if (obt->actcol > obt->totcol) { | if (obt->actcol > obt->totcol) { | ||||
| obt->actcol = obt->totcol; | obt->actcol = obt->totcol; | ||||
| } | } | ||||
| if (obt->totcol == 0) { | if (obt->totcol == 0) { | ||||
| MEM_freeN(obt->mat); | MEM_freeN(obt->mat); | ||||
| MEM_freeN(obt->matbits); | MEM_freeN(obt->matbits); | ||||
| obt->mat = NULL; | obt->mat = nullptr; | ||||
| obt->matbits = NULL; | obt->matbits = nullptr; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* check indices from mesh */ | /* check indices from mesh */ | ||||
| if (ELEM(ob->type, OB_MESH, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { | if (ELEM(ob->type, OB_MESH, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { | ||||
| material_data_index_remove_id((ID *)ob->data, actcol - 1); | material_data_index_remove_id((ID *)ob->data, actcol - 1); | ||||
| if (ob->runtime.curve_cache) { | if (ob->runtime.curve_cache) { | ||||
| BKE_displist_free(&ob->runtime.curve_cache->disp); | BKE_displist_free(&ob->runtime.curve_cache->disp); | ||||
| } | } | ||||
| } | } | ||||
| /* check indices from gpencil */ | /* check indices from gpencil */ | ||||
| else if (ob->type == OB_GPENCIL) { | else if (ob->type == OB_GPENCIL) { | ||||
| BKE_gpencil_material_index_reassign((bGPdata *)ob->data, ob->totcol, actcol - 1); | BKE_gpencil_material_index_reassign((bGPdata *)ob->data, ob->totcol, actcol - 1); | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| static bNode *nodetree_uv_node_recursive(bNode *node) | static bNode *nodetree_uv_node_recursive(bNode *node) | ||||
| { | { | ||||
| bNode *inode; | bNode *inode; | ||||
| bNodeSocket *sock; | bNodeSocket *sock; | ||||
| for (sock = node->inputs.first; sock; sock = sock->next) { | for (sock = static_cast<bNodeSocket *>(node->inputs.first); sock; sock = sock->next) { | ||||
| if (sock->link) { | if (sock->link) { | ||||
| inode = sock->link->fromnode; | inode = sock->link->fromnode; | ||||
| if (inode->typeinfo->nclass == NODE_CLASS_INPUT && inode->typeinfo->type == SH_NODE_UVMAP) { | if (inode->typeinfo->nclass == NODE_CLASS_INPUT && inode->typeinfo->type == SH_NODE_UVMAP) { | ||||
| return inode; | return inode; | ||||
| } | } | ||||
| return nodetree_uv_node_recursive(inode); | return nodetree_uv_node_recursive(inode); | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| /** Bitwise filter for updating paint slots. */ | /** Bitwise filter for updating paint slots. */ | ||||
| typedef enum ePaintSlotFilter { | typedef enum ePaintSlotFilter { | ||||
| PAINT_SLOT_IMAGE = 1 << 0, | PAINT_SLOT_IMAGE = 1 << 0, | ||||
| PAINT_SLOT_COLOR_ATTRIBUTE = 1 << 1, | PAINT_SLOT_COLOR_ATTRIBUTE = 1 << 1, | ||||
| } ePaintSlotFilter; | } ePaintSlotFilter; | ||||
| ENUM_OPERATORS(ePaintSlotFilter, PAINT_SLOT_COLOR_ATTRIBUTE) | |||||
| typedef bool (*ForEachTexNodeCallback)(bNode *node, void *userdata); | typedef bool (*ForEachTexNodeCallback)(bNode *node, void *userdata); | ||||
| static bool ntree_foreach_texnode_recursive(bNodeTree *nodetree, | static bool ntree_foreach_texnode_recursive(bNodeTree *nodetree, | ||||
| ForEachTexNodeCallback callback, | ForEachTexNodeCallback callback, | ||||
| void *userdata, | void *userdata, | ||||
| ePaintSlotFilter slot_filter) | ePaintSlotFilter slot_filter) | ||||
| { | { | ||||
| const bool do_image_nodes = (slot_filter & PAINT_SLOT_IMAGE) != 0; | const bool do_image_nodes = (slot_filter & PAINT_SLOT_IMAGE) != 0; | ||||
| Show All 40 Lines | struct FillTexPaintSlotsData { | ||||
| const Object *ob; | const Object *ob; | ||||
| Material *ma; | Material *ma; | ||||
| int index; | int index; | ||||
| int slot_len; | int slot_len; | ||||
| }; | }; | ||||
| static bool fill_texpaint_slots_cb(bNode *node, void *userdata) | static bool fill_texpaint_slots_cb(bNode *node, void *userdata) | ||||
| { | { | ||||
| struct FillTexPaintSlotsData *fill_data = userdata; | struct FillTexPaintSlotsData *fill_data = static_cast<FillTexPaintSlotsData *>(userdata); | ||||
| Material *ma = fill_data->ma; | Material *ma = fill_data->ma; | ||||
| int index = fill_data->index; | int index = fill_data->index; | ||||
| fill_data->index++; | fill_data->index++; | ||||
| if (fill_data->active_node == node) { | if (fill_data->active_node == node) { | ||||
| ma->paint_active_slot = index; | ma->paint_active_slot = index; | ||||
| } | } | ||||
| Show All 18 Lines | case SH_NODE_TEX_IMAGE: { | ||||
| /* just invalidate the index here so UV map does not get displayed on the UI */ | /* just invalidate the index here so UV map does not get displayed on the UI */ | ||||
| slot->valid = false; | slot->valid = false; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case SH_NODE_ATTRIBUTE: { | case SH_NODE_ATTRIBUTE: { | ||||
| TexPaintSlot *slot = &ma->texpaintslot[index]; | TexPaintSlot *slot = &ma->texpaintslot[index]; | ||||
| NodeShaderAttribute *storage = node->storage; | NodeShaderAttribute *storage = static_cast<NodeShaderAttribute *>(node->storage); | ||||
| slot->attribute_name = storage->name; | slot->attribute_name = storage->name; | ||||
| if (storage->type == SHD_ATTRIBUTE_GEOMETRY) { | if (storage->type == SHD_ATTRIBUTE_GEOMETRY) { | ||||
| const Mesh *mesh = (const Mesh *)fill_data->ob->data; | const Mesh *mesh = (const Mesh *)fill_data->ob->data; | ||||
| const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name); | const CustomDataLayer *layer = BKE_id_attributes_color_find(&mesh->id, storage->name); | ||||
| slot->valid = layer != NULL; | slot->valid = layer != nullptr; | ||||
| } | } | ||||
| /* Do not show unsupported attributes. */ | /* Do not show unsupported attributes. */ | ||||
| if (!slot->valid) { | if (!slot->valid) { | ||||
| slot->attribute_name = NULL; | slot->attribute_name = nullptr; | ||||
| fill_data->index--; | fill_data->index--; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| return fill_data->index != fill_data->slot_len; | return fill_data->index != fill_data->slot_len; | ||||
| Show All 28 Lines | void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma, const struct Object *ob) | ||||
| const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob); | const ePaintSlotFilter slot_filter = material_paint_slot_filter(ob); | ||||
| const TexPaintSlot *prev_texpaintslot = ma->texpaintslot; | const TexPaintSlot *prev_texpaintslot = ma->texpaintslot; | ||||
| const int prev_paint_active_slot = ma->paint_active_slot; | const int prev_paint_active_slot = ma->paint_active_slot; | ||||
| const int prev_paint_clone_slot = ma->paint_clone_slot; | const int prev_paint_clone_slot = ma->paint_clone_slot; | ||||
| const int prev_tot_slots = ma->tot_slots; | const int prev_tot_slots = ma->tot_slots; | ||||
| ma->texpaintslot = NULL; | ma->texpaintslot = nullptr; | ||||
| ma->tot_slots = 0; | ma->tot_slots = 0; | ||||
| if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) { | if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) { | ||||
| ma->paint_active_slot = 0; | ma->paint_active_slot = 0; | ||||
| ma->paint_clone_slot = 0; | ma->paint_clone_slot = 0; | ||||
| } | } | ||||
| else if (!(ma->nodetree)) { | else if (!(ma->nodetree)) { | ||||
| ma->paint_active_slot = 0; | ma->paint_active_slot = 0; | ||||
| ma->paint_clone_slot = 0; | ma->paint_clone_slot = 0; | ||||
| } | } | ||||
| else { | else { | ||||
| int count = count_texture_nodes_recursive(ma->nodetree, slot_filter); | int count = count_texture_nodes_recursive(ma->nodetree, slot_filter); | ||||
| if (count == 0) { | if (count == 0) { | ||||
| ma->paint_active_slot = 0; | ma->paint_active_slot = 0; | ||||
| ma->paint_clone_slot = 0; | ma->paint_clone_slot = 0; | ||||
| } | } | ||||
| else { | else { | ||||
| ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots"); | ma->texpaintslot = MEM_cnew_array<TexPaintSlot>(count, "texpaint_slots"); | ||||
| bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree); | bNode *active_node = nodeGetActivePaintCanvas(ma->nodetree); | ||||
| fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter); | fill_texpaint_slots_recursive(ma->nodetree, active_node, ob, ma, count, slot_filter); | ||||
| ma->tot_slots = count; | ma->tot_slots = count; | ||||
| if (ma->paint_active_slot >= count) { | if (ma->paint_active_slot >= count) { | ||||
| Show All 29 Lines | |||||
| struct FindTexPaintNodeData { | struct FindTexPaintNodeData { | ||||
| TexPaintSlot *slot; | TexPaintSlot *slot; | ||||
| bNode *r_node; | bNode *r_node; | ||||
| }; | }; | ||||
| static bool texpaint_slot_node_find_cb(bNode *node, void *userdata) | static bool texpaint_slot_node_find_cb(bNode *node, void *userdata) | ||||
| { | { | ||||
| struct FindTexPaintNodeData *find_data = userdata; | struct FindTexPaintNodeData *find_data = static_cast<FindTexPaintNodeData *>(userdata); | ||||
| if (find_data->slot->ima && node->type == SH_NODE_TEX_IMAGE) { | if (find_data->slot->ima && node->type == SH_NODE_TEX_IMAGE) { | ||||
| Image *node_ima = (Image *)node->id; | Image *node_ima = (Image *)node->id; | ||||
| if (find_data->slot->ima == node_ima) { | if (find_data->slot->ima == node_ima) { | ||||
| find_data->r_node = node; | find_data->r_node = node; | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| if (find_data->slot->attribute_name && node->type == SH_NODE_ATTRIBUTE) { | if (find_data->slot->attribute_name && node->type == SH_NODE_ATTRIBUTE) { | ||||
| NodeShaderAttribute *storage = node->storage; | NodeShaderAttribute *storage = static_cast<NodeShaderAttribute *>(node->storage); | ||||
| if (STREQLEN(find_data->slot->attribute_name, storage->name, sizeof(storage->name))) { | if (STREQLEN(find_data->slot->attribute_name, storage->name, sizeof(storage->name))) { | ||||
| find_data->r_node = node; | find_data->r_node = node; | ||||
| return false; | return false; | ||||
| } | } | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| bNode *BKE_texpaint_slot_material_find_node(Material *ma, short texpaint_slot) | bNode *BKE_texpaint_slot_material_find_node(Material *ma, short texpaint_slot) | ||||
| { | { | ||||
| TexPaintSlot *slot = &ma->texpaintslot[texpaint_slot]; | TexPaintSlot *slot = &ma->texpaintslot[texpaint_slot]; | ||||
| struct FindTexPaintNodeData find_data = {slot, NULL}; | struct FindTexPaintNodeData find_data = {slot, nullptr}; | ||||
| ntree_foreach_texnode_recursive(ma->nodetree, | ntree_foreach_texnode_recursive(ma->nodetree, | ||||
| texpaint_slot_node_find_cb, | texpaint_slot_node_find_cb, | ||||
| &find_data, | &find_data, | ||||
| PAINT_SLOT_IMAGE | PAINT_SLOT_COLOR_ATTRIBUTE); | PAINT_SLOT_IMAGE | PAINT_SLOT_COLOR_ATTRIBUTE); | ||||
| return find_data.r_node; | return find_data.r_node; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 254 Lines • ▼ Show 20 Lines | |||||
| * \note matcopybuf.nodetree does _NOT_ use ID's | * \note matcopybuf.nodetree does _NOT_ use ID's | ||||
| * \todo matcopybuf.nodetree's node->id's are NOT validated, this will crash! | * \todo matcopybuf.nodetree's node->id's are NOT validated, this will crash! | ||||
| */ | */ | ||||
| static Material matcopybuf; | static Material matcopybuf; | ||||
| static short matcopied = 0; | static short matcopied = 0; | ||||
| void BKE_material_copybuf_clear(void) | void BKE_material_copybuf_clear(void) | ||||
| { | { | ||||
| memset(&matcopybuf, 0, sizeof(Material)); | matcopybuf = blender::dna::shallow_zero_initialize(); | ||||
| matcopied = 0; | matcopied = 0; | ||||
| } | } | ||||
| void BKE_material_copybuf_free(void) | void BKE_material_copybuf_free(void) | ||||
| { | { | ||||
| if (matcopybuf.nodetree) { | if (matcopybuf.nodetree) { | ||||
| ntreeFreeLocalTree(matcopybuf.nodetree); | ntreeFreeLocalTree(matcopybuf.nodetree); | ||||
| BLI_assert(!matcopybuf.nodetree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ | BLI_assert(!matcopybuf.nodetree->id.py_instance); /* Or call #BKE_libblock_free_data_py. */ | ||||
| MEM_freeN(matcopybuf.nodetree); | MEM_freeN(matcopybuf.nodetree); | ||||
| matcopybuf.nodetree = NULL; | matcopybuf.nodetree = nullptr; | ||||
| } | } | ||||
| matcopied = 0; | matcopied = 0; | ||||
| } | } | ||||
| void BKE_material_copybuf_copy(Main *bmain, Material *ma) | void BKE_material_copybuf_copy(Main *bmain, Material *ma) | ||||
| { | { | ||||
| if (matcopied) { | if (matcopied) { | ||||
| BKE_material_copybuf_free(); | BKE_material_copybuf_free(); | ||||
| } | } | ||||
| memcpy(&matcopybuf, ma, sizeof(Material)); | matcopybuf = blender::dna::shallow_copy(*ma); | ||||
| if (ma->nodetree != NULL) { | if (ma->nodetree != nullptr) { | ||||
| matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false); | matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, bmain, false); | ||||
| } | } | ||||
| matcopybuf.preview = NULL; | matcopybuf.preview = nullptr; | ||||
| BLI_listbase_clear(&matcopybuf.gpumaterial); | BLI_listbase_clear(&matcopybuf.gpumaterial); | ||||
| /* TODO: Duplicate Engine Settings and set runtime to NULL. */ | /* TODO: Duplicate Engine Settings and set runtime to nullptr. */ | ||||
| matcopied = 1; | matcopied = 1; | ||||
| } | } | ||||
| void BKE_material_copybuf_paste(Main *bmain, Material *ma) | void BKE_material_copybuf_paste(Main *bmain, Material *ma) | ||||
| { | { | ||||
| ID id; | ID id; | ||||
| if (matcopied == 0) { | if (matcopied == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* Free gpu material before the ntree */ | /* Free gpu material before the ntree */ | ||||
| GPU_material_free(&ma->gpumaterial); | GPU_material_free(&ma->gpumaterial); | ||||
| if (ma->nodetree) { | if (ma->nodetree) { | ||||
| ntreeFreeEmbeddedTree(ma->nodetree); | ntreeFreeEmbeddedTree(ma->nodetree); | ||||
| MEM_freeN(ma->nodetree); | MEM_freeN(ma->nodetree); | ||||
| } | } | ||||
| id = (ma->id); | id = (ma->id); | ||||
| memcpy(ma, &matcopybuf, sizeof(Material)); | *ma = blender::dna::shallow_copy(matcopybuf); | ||||
| (ma->id) = id; | (ma->id) = id; | ||||
| if (matcopybuf.nodetree != NULL) { | if (matcopybuf.nodetree != nullptr) { | ||||
| ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false); | ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, bmain, false); | ||||
| } | } | ||||
| } | } | ||||
| void BKE_material_eval(struct Depsgraph *depsgraph, Material *material) | void BKE_material_eval(struct Depsgraph *depsgraph, Material *material) | ||||
| { | { | ||||
| DEG_debug_print_eval(depsgraph, __func__, material->id.name, material); | DEG_debug_print_eval(depsgraph, __func__, material->id.name, material); | ||||
| GPU_material_free(&material->gpumaterial); | GPU_material_free(&material->gpumaterial); | ||||
| Show All 10 Lines | |||||
| static Material default_material_volume; | static Material default_material_volume; | ||||
| static Material default_material_gpencil; | static Material default_material_gpencil; | ||||
| static Material *default_materials[] = {&default_material_empty, | static Material *default_materials[] = {&default_material_empty, | ||||
| &default_material_holdout, | &default_material_holdout, | ||||
| &default_material_surface, | &default_material_surface, | ||||
| &default_material_volume, | &default_material_volume, | ||||
| &default_material_gpencil, | &default_material_gpencil, | ||||
| NULL}; | nullptr}; | ||||
| static void material_default_gpencil_init(Material *ma) | static void material_default_gpencil_init(Material *ma) | ||||
| { | { | ||||
| strcpy(ma->id.name, "MADefault GPencil"); | strcpy(ma->id.name, "MADefault GPencil"); | ||||
| BKE_gpencil_material_attr_init(ma); | BKE_gpencil_material_attr_init(ma); | ||||
| add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f); | add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f); | ||||
| } | } | ||||
| static void material_default_surface_init(Material *ma) | static void material_default_surface_init(Material *ma) | ||||
| { | { | ||||
| strcpy(ma->id.name, "MADefault Surface"); | strcpy(ma->id.name, "MADefault Surface"); | ||||
| bNodeTree *ntree = ntreeAddTreeEmbedded( | bNodeTree *ntree = ntreeAddTreeEmbedded( | ||||
| NULL, &ma->id, "Shader Nodetree", ntreeType_Shader->idname); | nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname); | ||||
| ma->use_nodes = true; | ma->use_nodes = true; | ||||
| bNode *principled = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_PRINCIPLED); | bNode *principled = nodeAddStaticNode(nullptr, ntree, SH_NODE_BSDF_PRINCIPLED); | ||||
| bNodeSocket *base_color = nodeFindSocket(principled, SOCK_IN, "Base Color"); | bNodeSocket *base_color = nodeFindSocket(principled, SOCK_IN, "Base Color"); | ||||
| copy_v3_v3(((bNodeSocketValueRGBA *)base_color->default_value)->value, &ma->r); | copy_v3_v3(((bNodeSocketValueRGBA *)base_color->default_value)->value, &ma->r); | ||||
| bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); | bNode *output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL); | ||||
| nodeAddLink(ntree, | nodeAddLink(ntree, | ||||
| principled, | principled, | ||||
| nodeFindSocket(principled, SOCK_OUT, "BSDF"), | nodeFindSocket(principled, SOCK_OUT, "BSDF"), | ||||
| output, | output, | ||||
| nodeFindSocket(output, SOCK_IN, "Surface")); | nodeFindSocket(output, SOCK_IN, "Surface")); | ||||
| principled->locx = 10.0f; | principled->locx = 10.0f; | ||||
| principled->locy = 300.0f; | principled->locy = 300.0f; | ||||
| output->locx = 300.0f; | output->locx = 300.0f; | ||||
| output->locy = 300.0f; | output->locy = 300.0f; | ||||
| nodeSetActive(ntree, output); | nodeSetActive(ntree, output); | ||||
| } | } | ||||
| static void material_default_volume_init(Material *ma) | static void material_default_volume_init(Material *ma) | ||||
| { | { | ||||
| strcpy(ma->id.name, "MADefault Volume"); | strcpy(ma->id.name, "MADefault Volume"); | ||||
| bNodeTree *ntree = ntreeAddTreeEmbedded( | bNodeTree *ntree = ntreeAddTreeEmbedded( | ||||
| NULL, &ma->id, "Shader Nodetree", ntreeType_Shader->idname); | nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname); | ||||
| ma->use_nodes = true; | ma->use_nodes = true; | ||||
| bNode *principled = nodeAddStaticNode(NULL, ntree, SH_NODE_VOLUME_PRINCIPLED); | bNode *principled = nodeAddStaticNode(nullptr, ntree, SH_NODE_VOLUME_PRINCIPLED); | ||||
| bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); | bNode *output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL); | ||||
| nodeAddLink(ntree, | nodeAddLink(ntree, | ||||
| principled, | principled, | ||||
| nodeFindSocket(principled, SOCK_OUT, "Volume"), | nodeFindSocket(principled, SOCK_OUT, "Volume"), | ||||
| output, | output, | ||||
| nodeFindSocket(output, SOCK_IN, "Volume")); | nodeFindSocket(output, SOCK_IN, "Volume")); | ||||
| principled->locx = 10.0f; | principled->locx = 10.0f; | ||||
| principled->locy = 300.0f; | principled->locy = 300.0f; | ||||
| output->locx = 300.0f; | output->locx = 300.0f; | ||||
| output->locy = 300.0f; | output->locy = 300.0f; | ||||
| nodeSetActive(ntree, output); | nodeSetActive(ntree, output); | ||||
| } | } | ||||
| static void material_default_holdout_init(Material *ma) | static void material_default_holdout_init(Material *ma) | ||||
| { | { | ||||
| strcpy(ma->id.name, "MADefault Holdout"); | strcpy(ma->id.name, "MADefault Holdout"); | ||||
| bNodeTree *ntree = ntreeAddTreeEmbedded( | bNodeTree *ntree = ntreeAddTreeEmbedded( | ||||
| NULL, &ma->id, "Shader Nodetree", ntreeType_Shader->idname); | nullptr, &ma->id, "Shader Nodetree", ntreeType_Shader->idname); | ||||
| ma->use_nodes = true; | ma->use_nodes = true; | ||||
| bNode *holdout = nodeAddStaticNode(NULL, ntree, SH_NODE_HOLDOUT); | bNode *holdout = nodeAddStaticNode(nullptr, ntree, SH_NODE_HOLDOUT); | ||||
| bNode *output = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL); | bNode *output = nodeAddStaticNode(nullptr, ntree, SH_NODE_OUTPUT_MATERIAL); | ||||
| nodeAddLink(ntree, | nodeAddLink(ntree, | ||||
| holdout, | holdout, | ||||
| nodeFindSocket(holdout, SOCK_OUT, "Holdout"), | nodeFindSocket(holdout, SOCK_OUT, "Holdout"), | ||||
| output, | output, | ||||
| nodeFindSocket(output, SOCK_IN, "Surface")); | nodeFindSocket(output, SOCK_IN, "Surface")); | ||||
| holdout->locx = 10.0f; | holdout->locx = 10.0f; | ||||
| ▲ Show 20 Lines • Show All 62 Lines • Show Last 20 Lines | |||||